如何防止 unordered_map.find() 被比作错误的结束迭代器?[已结束]

How to prevent unordered_map.find() being compared to a wrong end iterator? [closed]

提问人:Ivan Krivyakov 提问时间:10/3/2023 最后编辑:Ivan Krivyakov 更新时间:10/3/2023 访问量:81

问:


想改进这个问题吗?更新问题,以便可以通过编辑这篇文章来用事实和引文来回答。

上个月关闭。

我们刚刚在代码中发现了一个错误,它是这样的:

class foo {
    unordered_map<int,string> m_someMap;
public:
     void stuff() {
        unordered_map<int, string> someMap;
        ...
        auto it = someMap.find(x);
        if (it != m_someMap.end()) { // oops! comparing to the end() of a wrong map!
             // found x in the map, use it->second here 
        }
     }
}

这里明显的问题是,检查是否成功需要对地图进行两次命名,如果这两次出现不同步,用户要小心。find()

防止这种情况的最佳做法是什么?换言之,如何检查项目是否存在于地图中,而不必说出地图名称两次?

我希望地图迭代器可以转换为 ,这样我就可以写简单的 ,但它们不是。boolif (it)...

还有其他想法吗? 模板函数,返回 ?现代标准库的一些魔力?safe_find()optional<unordered_map<int,string>::iterator>>

C++ 字典 STL 迭代器 无序映射

评论

1赞 273K 10/3/2023
还有其他想法吗?这取决于进一步的使用情况。因此,描述什么是。itfound x
1赞 molbdnilo 10/3/2023
在我看来,这个建议还不错。optional
0赞 Ivan Krivyakov 10/4/2023
如果找到迭代器,我应该更清楚地表明我确实在使用迭代器,我不仅在检查密钥是否存在。固定。

答:

1赞 kiner_shah 10/3/2023 #1

您可以创建一个免费的模板功能,以避免任何事故:

template<typename K, typename V>
static bool exists_in_unordered_map(const std::unordered_map<K, V>& m, const K& key)
{
    return m.find(key) != m.end();
}

然后随时随地使用它:

if (exists_in_unordered_map(someMap, x))
{
    // found x, now do something here
}
0赞 Öö Tiib 10/3/2023 #2

最常见的做法是在测试版本中使用调试选项,如 clang、gcc 或 msvc。_LIBCPP_DEBUG_GLIBCXX_DEBUG_ITERATOR_DEBUG_LEVEL

这将导致大量的运行时健全性检查,例如不相关的迭代器不会相互比较。因此,您描述的缺陷(以及许多其他缺陷)将更快地被发现和修复。

编写一些运行时检查或辅助逻辑感觉更糟糕。一旦编程错误被修复,那么检查可能只会浪费最终产品的运行时性能,而C++正是因为这种良好的性能而最常用的。

1赞 alagner 10/3/2023 #3

您只需要检查给定键是否存在,还是也需要对找到的元素进行检查?有很多选择,具体取决于要实现的目标和使用的语言版本。

  1. 返回指针的自定义模板方法,可选,您可以命名它。这是不言自明的。这里很难给出详尽的答案,可以通过多种方式实现。 我可能会选择这样的 sth:
#include <map>
#include <optional>
#include <functional>
#include <type_traits>

template<typename M, typename K>
auto mapFind(M& map, const K& key)
{
    using MappedType = 
        std::conditional_t<std::is_const_v<M>,
            const typename M::mapped_type,
            typename M::mapped_type>;
    using ReturnType = std::optional<std::reference_wrapper<MappedType>>;
    auto found = map.find(key);
    if (found == map.end()) {
        return ReturnType{std::nullopt};
    }
    return ReturnType{found->second};
}

https://godbolt.org/z/q1qbxKMs7

  1. map::包含来自 C++20。返回一个布尔值。mapObject.contains(key);
  2. map::count pre C++20 方式的第二点。稍微丑一点,但有效。mapObject.count(key) > 0;
  3. 地图::at基于例外,因此经常不喜欢或劝阻,但有效。try { mapObject.at(key); } catch (const std::out_of_range& ex) {//handle ex here}