【问题标题】:Erasing while traversing in C++ stl map giving runtime error在 C++ stl 映射中遍历时擦除会产生运行时错误
【发布时间】:2021-08-09 04:24:28
【问题描述】:

以下 C++ 代码行会产生运行时错误,但如果删除操作 mymap.erase(v) 则它可以工作:

map<int,int> mymap = {{1,0},{2,1},{9,2},{10,3},{11,4}};
for(auto it=mymap.rbegin();it!=mymap.rend();){
    int v=it->first;
    ++it;
    mymap.erase(v);
}

demo

这里迭代器 it 在删除其值 v 之前已更改,因此我相信迭代器 it 应该不受影响。

【问题讨论】:

  • 为我工作,见here,你能提供一个minimal, reproducible example吗?
  • 对我来说失败了:ideone.com/MVpW8S
  • @user4581301 你取消引用mymap.rend()
  • 以后不再添加演示作为评论,而是编辑帖子以包含它。这次我做到了。
  • 我认为问题出在反向迭代器上,当使用 begin/end 而不是 rbegin/rend 时它可以正常工作。

标签: c++ stl iterator stdmap


【解决方案1】:

当您调用erase(v) 时,您正在使下一个reverse_iterator(来自++it)正在使用的base iterator 无效。因此,您需要从已擦除值之前的基础 iterator 创建一个新的 reverse_iterator

另外,不要删除reverse_iterator 所指的,您应该删除基础iterator,因为您已经知道要删除哪个元素。无需让map 再次寻找价值。

这对我有用:

map<int,int> mymap = {{1,0},{2,1},{9,2},{10,3},{11,4}};
for(auto it = mymap.rbegin(); it != mymap.rend(); ){
    auto v = --(it.base());
    v = mymap.erase(v);
    it = map<int,int>::reverse_iterator(v);
}

Demo

另一方面,这个循环本质上只是erase()'ing 来自mymap 的所有元素,因此更好的选择是改用mymap.clear()

【讨论】:

    【解决方案2】:

    确实,std::map::erase:

    对已擦除元素的引用和迭代器无效。其他引用和迭代器不受影响。

    但是std::reverse_iterator

    对于从迭代器 i 构造的反向迭代器 r,关系 &amp;*r == &amp;*(i-1) 始终为真(只要 r 是可解引用的);因此,从一个过去的迭代器构造的反向迭代器取消对序列中最后一个元素的引用。

    当您查看 cppreference 页面上的图像时,可能会更清楚。

    关键部分是“反向迭代器将迭代器存储到下一个元素而不是它实际引用的元素”。

    因此(对您的代码进行小的修改)

    auto& element = *it;       // fails in the next iteration, because...
    int v = element.first;
    ++it;                      // now it stores an iterator to element
    mymap.erase(v);            // iterators to element are invalidated 
    

    您正在擦除it 在下一次迭代中使用的元素。

    【讨论】:

    • "实际上没有任何区别" - 从技术上讲,这个循环只是 erase()'ing 来自 map 的所有元素,所以是一个更好的选择改为mymap.clear()
    • @RemyLebeau 我实际上并没有意识到 :)
    • 仍然运行时错误link。 RemyLebeau 的另一个解决方案是正确的。我认为您的修改不会改变任何东西。变量 v 仍然包含相同的值。谢谢你的努力,虽然我不知道这些关于反向迭代器的事情。
    • @RemyLebeau 上下文非常复杂,我刚刚发布了我的具体问题。我不得不以相反的顺序删除一些元素
    • @PratapSingh erase-remove idiom 通常是你最好的朋友,当你发现自己在迭代时擦除。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-03-25
    • 2011-05-11
    • 1970-01-01
    • 1970-01-01
    • 2013-04-30
    • 2013-12-06
    • 1970-01-01
    相关资源
    最近更新 更多