C++11:在迭代时从std :: unordered_map中删除单个元素是否安全?

19

考虑在迭代过程中从关联式容器中移除元素的规范算法:

for (auto iter = myMap.begin(); iter != myMap.end(); )
{
    if (/* removal condition */)
    {
        iter = myMap.erase(iter);
    }
    else
    {
        ++iter;
    }
}

在使用C++11的std::unordered_map容器时,我一直毫不犹豫地应用这个算法。然而,在浏览cppreference.com上的std::unordered_map::erase文档后,我读到以下注意事项,感到有些担忧:

未被删除的元素的顺序是保留的(这使得可以在遍历容器时删除单个元素)(自C++14以来)

基于这个声明,我认为在C++14标准中添加了语言以确保库实现者保证调用std::unordered_map::erase后的排序。例如,这样的要求可能限制实现不能在删除元素后重新散列整个容器,而只允许它从相应的存储桶中删除元素。

如果没有C++11中的这种保证,并且如果我希望我的代码可移植,那么我必须担心如果我在遍历过程中从一个std::unordered_map中删除一个元素,某些元素是否会被访问多次或根本不被访问?


2
请参考这个答案,其中引用了C++11的规则。对于从无序关联容器中删除元素,只有指向被删除元素的迭代器会失效。因此,您的代码是有效的。 - Praetorian
8
抱歉,我误解了你的问题。这是导致措辞变化的问题链接。我认为你的问题的答案是 - 在 C++14 之前的标准中没有保证,但在实践中是有保证的。链接的报告也说明了这一点 - 实际上没有任何实现这样做。我会重新开放这个问题,也许会有更好的答案供你参考。 - Praetorian
@Praetorian:你对一个好问题有一个好答案。请把它放在我可以点赞的地方。 :-) - Howard Hinnant
@Howard 谢谢你,但我希望像你这样至少了解一个std库实现的人能够发布一个答案。无论如何,已经有一个回答了,说明了我在评论中所说的内容。 - Praetorian
啊,没错:自从C++11以来,map::erase返回一个迭代器。我一直记得Effective STL中的模式:if( ) myMap.erase(it++); else ++it;但是你的更好。 - TemplateRex
显示剩余2条评论
1个回答

2

编辑:NoScript的危险性。我使用了NoScript,导致C11和C14选项卡显示为一个框。Praetorian的回答关于在实践中保证并且在C14中正式化是正确的。

**由于NoScript以下内容有误。

在cplusplus底部,它声明:

只有被移除元素的迭代器和引用无效。

其他不受影响。

未被操作删除的元素的迭代顺序会被保留。

http://www.cplusplus.com/reference/unordered_map/unordered_map/erase/

页面顶部声明它适用于C++11...所以,除非他们已经更新了C++14,否则我认为它也适用于C++11。Praetorian应该提供答案并检查他的答案,因为即使在C++11标准中没有保证(C++14是这些问题的修补程序),但在实践中是有保证的。

我找不到STL标准,好像我放错了地方,否则我可以去看看是否有可以指出的文本保证。:-/


谢谢提供额外的链接,但是当我查看该页面时,语句“未被操作删除的元素的相对迭代顺序被保留”仅在C++14选项卡下列出。如果我读错了,请纠正我。否则,我希望进行编辑,因为我认为引用cplusplus.com链接很有用。 - f1191994
我开了无脚本模式。它把两个标签都显示成一个文本块。非常抱歉 :-( - Caladain
我接受了这个答案,因为它涉及到了上面Praetorian的评论,而这正是我所寻找的。 - f1191994

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接