如果我在iterator
循环中使用for
并且在迭代器的当前迭代中使用erase
,那么for循环应该继续正常并访问其余的{ {1}}元素?
从我所读到的情况来看,这应该是这种情况,是list
与list
或deque
的主要区别特征。就我的目的而言,vector
可能有用,但我需要这种行为。
这是我正在考虑的循环:
queue
答案 0 :(得分:48)
编写该循环的惯用方法是:
for (auto i = list.begin(); i != list.end();) {
if (condition)
i = list.erase(i);
else
++i;
}
您可以使用set
,multiset
,map
或multimap
执行相同的操作。对于这些容器,您可以擦除元素,而不会影响对其他元素的任何迭代器的有效性。其他容器如vector
或deque
并不那么友善。对于那些容器,只有擦除迭代器之前的元素保持不变。这种差异仅仅是因为list
在单独分配的节点中存储元素。一个链接很容易。 vector
是连续的,取出一个元素后,将所有元素移回一个位置后。
你的循环被破坏是因为你在某些特定条件下删除i
处的元素。在该调用之后,i
不再是有效的迭代器。然后,您的for
循环会增加i
,但i
无效。地狱般的地狱随之而来。这就是为什么erase
在删除之后将迭代器返回到元素的确切情况......所以你可以继续遍历list
。
您也可以使用list::remove_if
:
list.remove_if([](auto& i) { return i > 10; });
在lambda中,如果要删除元素,则返回true。在此示例中,它将删除大于10的所有元素。
答案 1 :(得分:0)
for (auto i = list.begin(); i != list.end(); ++i) {
if (condition) {
list.erase(i);
--i;
}
}
答案 2 :(得分:0)
如果您只想用于迭代器,则可以通过这种方式使用它,例如:
list<int> lst{4, 1, 2, 3, 5};
for(auto it = lst.begin(); it != lst.end();++it){
if ((*it % 2) == 1){
it = lst.erase(it); erase and go to next(erase will return the next iterator)
--it; // as it will be add again in for, so we go back one step
}
}
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
但是在while
迭代器中擦除将更加清晰:
list<int> lst{4, 1, 2, 3, 5};
auto it = lst.begin();
while (it != lst.end()){
if((*it % 2) == 1){
it = lst.erase(it);// erase and go to next
} else{
++it; // go to next
}
}
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
您还可以使用成员函数remove_if
:
list<int> lst{4, 1, 2, 3, 5};
lst.remove_if([](int a){return a % 2 == 1;});
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
或将std::remove_if
结合使用erase
功能:
list<int> lst{4, 1, 2, 3, 5};
lst.erase(std::remove_if(lst.begin(), lst.end(), [](int a){
return a % 2 == 1;
}), lst.end());
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
您还可以参考以下问题: Removing item from vector, while in C++11 range 'for' loop?