容器调用了自己的erase方法,接下来怎么办

erase函数的原型如下:
(1)string& erase ( size_t pos = 0, size_t n = npos );
(2)iterator erase ( iterator position );
(3)iterator erase ( iterator first, iterator last );
也就是说有三种用法:
(1)erase(pos,n); 删除从pos开始的n个字符,比如erase(0,1)就是删除第一个字符
(2)erase(position);删除position处的一个字符(position是个string类型的迭代器)
(3)erase(first,last);删除从first到last之间的字符(first和last都是迭代器)

例如下面的例子是去除程序中的空格

1  //  Utility function to trim whitespace off the ends of a string
2  inline std:: string  trim(std:: string  source)
3  {
4      std:: string  result  =  source.erase(source.find_last_not_of( "   " +   1 );
5       return  result.erase( 0 , result.find_first_not_of( "   " ));
6  }




今天写一个小例子时遇到了一个如下的问题:我要遍历一个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);//一定要这么写,今天是2015-2-6,又调试了几个小时在另一个项目里。尼玛
}
cout<<*i<<" ";
i++;
}

这样便可实现目的了,输出如下

容器调用了自己的erase方法,接下来怎么办_第1张图片




你可能感兴趣的:(容器调用了自己的erase方法,接下来怎么办)