在调试向量时,我发现不一致。假设以下代码尝试从只有一个元素的向量中删除条目
#include <iostream>
#include <vector>
std::vector<int> v;
void myremove(int);
int main()
{
v.push_back(10);
std::cout << "10 pushed back\n";
myremove(10);
std::cout << "done :)\n";
return 0;
}
void myremove( int a )
{
std::vector<int>::iterator it = v.begin();
int counter = 0;
for ( ; it != v.end(); it++ ) {
std::cout << "iterating for " << counter << " times and vector size is " << v.size() << "\n";
if ( a == (*it) ) {
v.erase(it);
std::cout << "removed " << a << "\n";
}
++counter;
}
}
这是我在输出中看到的:
$ g++ test.cpp
$ ./a.out | more
10 pushed back
iterating for 0 times and vector size is 1
removed 10
iterating for 1 times and vector size is 0
iterating for 2 times and vector size is 0
iterating for 3 times and vector size is 0
iterating for 4 times and vector size is 0
iterating for 5 times and vector size is 0
iterating for 6 times and vector size is 0
....
....
iterating for 33790 times and vector size is 0
Segmentation fault
我理解的是,当元素被移除时,大小将变为0,但迭代器移动一步仍然会尝试到达终点,但他不知道他已经通过了终点。
有人可以解释发生了什么以及如何避免这种情况吗?
答案 0 :(得分:6)
调用erase()
后,迭代器it
无效:
对擦除元素以及它们与容器末尾之间元素的迭代器和引用无效。
将it
设置为erase()
的返回值,只有在没有删除时才会递增:
while (it != v.end())
{
if ( a == (*it) )
{
it = v.erase(it);
std::cout << "removed " << a << "\n";
}
else
{
++it;
}
}
erase()
的返回值为:
最后一个删除元素之后的迭代器。
而不是手动编码循环来擦除元素,而不是使用std::remove_if()
:
v.erase(std::remove_if(v.begin(),
v.end(),
[](const int i) { return i == 10; }),
v.end());
答案 1 :(得分:4)
擦除时
v.erase(it);
你的迭代器不再有效了。您必须使用擦除返回的迭代器。擦除为您提供一个迭代器,指向调用擦除元素后面的元素。如果你在循环增加it
之前删除了最后一个元素,那么你必须打破循环。
it = v.erase(it);
if(it == v.end())
break;
建议:您可以继续将for循环更改为while循环。并明确地增加迭代器(即只有当你没有删除任何东西时。如果你已经删除了迭代器,那么已经增加了)。
喜欢这个
while(it != v.end()) {
if ( a == (*it) )
it = v.erase(it);
else
++it;
}
答案 2 :(得分:0)
每次插入和擦除都会使容器的所有迭代器无效。插入/擦除后,这些方法返回ONLY有效的迭代器。
答案 3 :(得分:0)
在std::vector::erase
的文档中:
迭代器有效期
删除循环中的元素(取决于迭代器)会使一切都发狂。这就是它!
答案 4 :(得分:0)
当你调用erase函数时,迭代器不再是有效的迭代器,当你增加无效迭代器时,你会得到虚假的结果。
答案 5 :(得分:0)
错误在于,在对迭代器进行擦除之后,您希望此迭代器仍处于一致状态。情况并非如此,您的代码会准确说明发生这种情况时的情况。
你的函数的语义是删除向量的所有元素等于a
。您可以通过过滤矢量来获得相同的结果。请看这个问题:
How to make std::vector from other vector with specific filter?