在 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);
}
此处迭代器 it
在删除其值 v
之前已更改,因此我相信迭代器 it
应该不受影响。
当您调用 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);
}
另一方面,这个循环本质上只是 erase()
'ing 来自 mymap
的所有元素,所以更好的选择是使用 mymap.clear()
。
的确如此,std::map::erase
:
References and iterators to the erased elements are invalidated. Other references and iterators are not affected.
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
在下一次迭代中使用的元素。
以下几行 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);
}
此处迭代器 it
在删除其值 v
之前已更改,因此我相信迭代器 it
应该不受影响。
当您调用 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);
}
另一方面,这个循环本质上只是 erase()
'ing 来自 mymap
的所有元素,所以更好的选择是使用 mymap.clear()
。
的确如此,std::map::erase
:
References and iterators to the erased elements are invalidated. Other references and iterators are not affected.
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
在下一次迭代中使用的元素。