今天写一个小例子时遇到了一个如下的问题:我要遍历一个vector,但遍历过程中某些条件具备的时候我就打算删除复合条件的元素。删除时使用erase永久删除,然后继续完成遍历(这个情况在Effective C++上面看到过,但没找到,还记得有解决办法的,所以就自己想办法了)。比如现在我打算在遍历遇到2的时候直接删除2,删除后的数组还可以当做它用。
int b[]={1,2,3,4,5};
vector<int> a(b,b+5);
for (vector<int>::iterator i=b.begin();i!=b.end();i++)
{
if(*i==2)
{
b.erase(i);
}
cout<<*i;
}
发现这样只能输出1,之后就非法访问了。原因在于erase删除迭代器所指向的元素后,迭代器便不再有效。
接下了考虑使用continue是不是可以跳过此次输出动作,直接从下一次开始:
for (vector<int>::iterator i=b.begin();i!=b.end();i++)
{
if(*i==2)
{
b.erase(i);
continue;
}
cout<<*i;
}
发现这样也不行,因为continue只是将此次循环还未执行完的部分跳过。但并不能阻止i++的执行。正是i++导致了问题。因为i++使用了已经失效的原来被删除的迭代器。为了避免这样的错误,所以要更新迭代器。由于erase自动返回被删除迭代器的下一个迭代器。所以新的程序如下
for (vector<int>::iterator i=b.begin();i!=b.end();i++)
{
if(*i==2)
{
i=b.erase(i);
}
else
cout<<*i;
}
此时输出的是 : 145 ,3哪去了呢?因为遇到2时,删除了指向2的迭代器,并更新迭代器使之指向3,但接下来执行了i++,这样就跳过了对3的判断和使用。即3被屏蔽了。
从上面可以看出i++是不可避免的问题来源。所以现在考虑让i++可被控制,让它当道循环体内部即可,也就是可以用while循环来实现。
vector<int>::iterator i=b.begin();
while(i!=b.end())
{
if (*i==2)
{
i=b.erase(i);
}
cout<<*i<<" ";
i++;
}
这样便可实现目的了,输出如下