STL的erase()陷阱

  • Post author:
  • Post category:其他



本文的目的


erase在删除容器中的元素时,由于

迭代器失效

会产生严重的错误;本文不讲太多的废话,直接从erase的使用性角度,总结了erase的通用使用套路,便于以后程序的开发。



容器分类


常见的容器有2大类,分别是:

节点式容器:(map, list, set)

顺序式容器:(vector,string,deque)



erase & 顺序式容器


在使用

顺序式容器

(vector,string,deque)遍历删除元素时,通常使用

erase的返回值

获取已删除元素的下一个元素的迭代器位置,保证迭代器不失效。

① 错误的代码

std::vector<struct> mFriendVec;
...
std::vector<struct>::iterator iter = mFriendVec.begin();
for ( std::vector<struct>::iterator iter = mVector.begin(); 
      iter != mFriendVec.end(); 
      ++iter
      )
{
    if (  willDelete(*iter)  )  // if若成立,程序肯定崩溃,为什么呢?
        mFriendVec.erase(iter);
}

② 正确的代码

std::vector<struct> mVector;
...
for ( std::vector<struct>::iterator iter = mVector.begin(); 
      iter != mVector.end(); 
      )
{
    if (  willDelete(*iter)  )  // 如果是待删除元素
    {
        //顺序式容器会使本身和后面的元素迭代器都失效,所以不能简单的++操作
        iter = mVector.erase(iter); //erase返回值 = 指向已删除元素的下一个元素的iterator
    }
    else  
    {
        ++iter; 
    }
}


erase & 节点式容器



总结

:无论是

节点式容器

还是

顺序式容器

,在对迭代器iter进行删除时,我们都使用

通用的万能公式

,代码见下。

std::list<int> List;
std::list<int>::iterator iter;
for( iter = List.begin(); iter != List.end(); )
{
      if( WillDelete( *iter ) )
      {
            iter = List.erase(iter);  //保存iterd的下一个元素
       }
       else
            iter++;
}