unordered_map:如果键不在地图中,返回啥?

Posted

技术标签:

【中文标题】unordered_map:如果键不在地图中,返回啥?【英文标题】:unordered_map: what to return if key is not in map?unordered_map:如果键不在地图中,返回什么? 【发布时间】:2013-10-12 01:02:48 【问题描述】:

作为这个问题的前言,我不得不说我是一名 Java 程序员,因此比 C++ 更习惯 Java 中的 Maps 语义。在 Java 中,当在 Map 中查找键时,这很常见并且预期会返回 null。我正在将我们的一些代码翻译成 c++,并尝试在与 unordered_map 交互时找到 c++ 的处理方式。

具体来说,我有一个包含 unordered_map 的类。我没有将映射直接暴露给客户端代码,而是有 2 个包装函数,一个用于将键/值对放入映射中,另一个用于检索指定键的值,即:

void set_tag_value(string tag, string value);

string& get_tag_value(string tag);

如果我使用unordered_map.at() 来检索值,那么它将引发我的代码需要捕获的异常,或者允许它传播到客户端代码。 (不过,将异常传播给我似乎不友好)。

也许另一种方法是将返回值更改为string* 类型,如果找不到则返回 NULL(这是 Java 的做法),但随后用户需要检查 NULL(这也不是如此友好)。

所以我的问题有两个部分:

    什么是开发人员友好的方式来处理失败的查找,什么返回值有用(异常、NULL、空字符串或其他)?

    在我的代码中,当您期望它可能找不到键、at() 并捕获异常或查找并检查迭代器 == map.end() 时,哪种映射查找方法更典型? (这部分问题是我只是想学习c++的做事方式)。

感谢您的建议!

【问题讨论】:

boost::optionalstd::optional (C++14)。 More details in my answer here. “C++ 方式”是让客户端访问 unordered_map 的完整接口,因此他们可以(例如)通过其迭代器对其应用标准算法。 @JerryCoffin:我经常对直接访问类内部数据结构感到不舒服,除非我觉得客户端代码有一些功能性用例可以将它作为对象访问。当然,在 Java 中,我经常发现随着代码的发展,我会更改底层数据结构,因此与它们绑定的任何东西也必须重新编译。在这种情况下,客户端不应该关心映射是如何存储的,他们只需要能够检索值(如果找不到值则不会出错)。 @SamGoldberg:关键是unordered_map 已经提供了一个相当抽象的接口,该接口功能强大且设计良好。更重要的是,每个了解 C++ 的人都已经知道如何使用它。您通过隐藏它所完成的所有工作就是为您的用户创建另一个(功能较弱的)界面来学习。 【参考方案1】:

在我看来,最好不要返回指向您保持私有的地图内容的指针,因为如果地图更改,这些指针可能会失效。

我会让函数返回一个成功代码 (bool) 并传递一个对字符串的引用以实际返回如果找到的值。例如,

bool get_tag_value(const string& tag, string& value)

    auto t = my_map.find(tag);
    if (t == my_map.end()) return false;
    value = t->second;
    return true;

请注意,如果未找到密钥,unordered_map::at() 将抛出,unordered_map::find() 返回无效的迭代器 (unordered_map::end()) - 因此您可以避免以这种方式处理异常。

如果您想坚持返回一个字符串,那么如果找不到密钥,则只需返回一个空字符串 (return string();)。

【讨论】:

【参考方案2】:

根据您使用 boost 的意愿,我会考虑以下 2 个选项:

返回一个指针:

/* const? */ string* get_tag_value_ptr(const string& tag)

    auto it = theMap.find(tag);
    if (it != theMap.end()) 
        return &it->second;
    

    return nullptr;

返回一个可选的参考:

boost::optional</* const? */ string&> get_tag_value_opt(const string& tag)

    auto it = theMap.find(tag);
    if (it != theMap.end()) 
        return it->second;
    

    return boost::none;

希望我们很快就会有std::optional,尽管它已经从 C++14 推迟了。

这些检索方法不需要从映射中复制值。通过 out 参数返回意味着复制该值。我想这取决于您的要求。

【讨论】:

升压建议不错。最后,我选择不使用它,只是为了将返回值保留为字符串以简化使用。在这个特定的应用程序中,空字符串是一个合理的返回值来暗示空虚。 (但在许多其他情况下,boost::optional 将是唯一的方法。)感谢您的想法。

以上是关于unordered_map:如果键不在地图中,返回啥?的主要内容,如果未能解决你的问题,请参考以下文章

将对象的属性作为字符串传递

为啥我不能更改 unordered_map 返回的对象的成员变量?

Map vs Unordered_map——多线程

从 unordered_map 获取键和值列表

迭代 unordered_map C++

std::unordered_map 如何表现? [C++]