在 C++ stl 映射中遍历时擦除给出运行时错误

Erasing while traversing in C++ stl map giving runtime error

以下几行 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 应该不受影响。

当您调用 erase(v) 时,您正在使下一个 reverse_iterator(来自 ++itbase 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()

的确如此,std::map::erase:

References and iterators to the erased elements are invalidated. Other references and iterators are not affected.

但是std::reverse_iterator

For a reverse iterator r constructed from an iterator i, the relationship &*r == &*(i-1) is always true (as long as r is dereferenceable); thus a reverse iterator constructed from a one-past-the-end iterator dereferences to the last element in a sequence.

也许当你在 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 在下一次迭代中使用的元素。