stl容器之erase用法

本人最近工作中用到std::list,在刪除元素時用到以下

      for( iterator= List.begin(); iterator!= List.end(); iterator++)
      {
            if( iterator->nIndex == nIndex)
            {
               List.erase( iterator);
            }
      }
結果可想而知,程序異常。在查找網上資料後知道erase方法使用不對,到了現在還犯這種錯誤,汗顏!吸取教訓~

下面將所找的資料貼出來,寫的很明白,就不再敷述。


===========================================================================================

【http://www.jb51.net/article/37437.htm】

基於C++ list中erase與remove函數的使用詳解

erase的作用是,使作爲參數的迭代器失效,並返回指向該迭代器下一參數的迭代器。
如下:

複製代碼代碼如下:

list ParticleSystem;
list::iterator pointer;
if(pointer->dead == true)
{
   pointer = ParticleSystem.erase(pointer);
}

有一段關於錯誤使用erase的程序
複製代碼代碼如下:

using namespace std;
int main()
{
  std::listtest_list;
  std::list::iterator test_list_it;
  test_list.push_back(1);
  test_list_it = test_list.begin();
  for(;test_list_it != test_list.end();test_list_it++)
  {
  test_list.erase(test_list_it);
  }
}

問題:該程序不能跳出循環
原因:test_list.erase(test_list_it);每次做erase時都有可能使迭代器失效,test_list_it++就發生錯誤了。可以參見effective stl一書。所有容器做erase操作時都有可能使迭代器失效。
改爲:
複製代碼代碼如下:

for(;test_list_it != test_list.end();)
{
    test_list.erase(test_list_it++);
}

or
複製代碼代碼如下:

for(;test_list_it != test_list.end();)
{
    std::list::iterator iter_e=test_list_it++;
    test_list.erase(iter_e);
}

注意:
複製代碼代碼如下:

for(;test_list_it != test_list.end();test_list_it++;) {
    std::list::iterator iter_e=test_list_it;
    test_list.erase(iter_e);
}

這樣仍然是錯誤的,原因是:iter_e=test_list_it 是指針值的複製,它倆其實指向同一個位置,所以iter_e失效那麼test_list_it也會失效,所以test_list_it++就會有問題
如果是
複製代碼代碼如下:

for(;test_list_it != test_list.end();)
{
    std::list::iterator iter_e=test_list_it++;
    test_list.erase(iter_e);
}

則沒有問題。
remove函數也存在erase函數同樣的問題,但remove函數返回值是空,erase返回指向下一個元素的迭代器


===========================================================================================

【http://www.cppblog.com/Herbert/archive/2009/01/08/70479.html】

   STL中的容器按存儲方式分爲兩類,一類是按以數組形式存儲的容器(如:vector 、deque);另一類是以不連續的節點形式存儲的容器(如:list、set、map)。在使用erase方法來刪除元素時,需要注意一些問題。
      在使用 list、set 或 map遍歷刪除某些元素時可以這樣使用:

正確使用方法1      std::list< int> List;
      std::list< int>::iterator itList;
      for( itList = List.begin(); itList != List.end(); )
      {
            if( WillDelete( *itList) )
            {
               itList = List.erase( itList);
            }
            else
               itList++;
      }

       或
正確使用方法2      std::list< int> List;
      std::list< int>::iterator itList;
      for( itList = List.begin(); itList != List.end(); )
      {
            if( WillDelete( *itList) )
            {
               List.erase( itList++);
            }
            else
               itList++;
      }

      下面是兩個錯誤的使用方法:

錯誤使用方法1      std::list< int> List;
      std::list< int>::iterator itList;
      for( itList = List.begin(); itList != List.end(); itList++)
      {
            if( WillDelete( *itList) )
            {
               List.erase( itList);
            }
      }

         或
錯誤使用方法2      std::list< int> List;
      std::list< int>::iterator itList;
      for( itList = List.begin(); itList != List.end(); )
      {
            if( WillDelete( *itList) )
            {
               itList = List.erase( ++itList);
            }
            else
               itList++;
      }

      正確使用方法1:通過erase方法的返回值來獲取下一個元素的位置
      正確使用方法2:在調用erase方法之前先使用 “++”來獲取下一個元素的位置
      錯誤使用方法1:在調用erase方法之後使用“++”來獲取下一個元素的位置,由於在調用erase方法以後,該元素的位置已經被刪除,如果在根據這個舊的位置來獲取下一個位置,則會出現異常。
      錯誤使用方法2:同上。

      這裏“++”運算符與我們平常的理解剛好相反,erase( itList++) 是先獲取下一個元素的位置在刪除; erase( ++itList) 是刪除以後再獲取下一個元素的位置。

     在使用 vector、deque遍歷刪除元素時,也可以通過erase的返回值來獲取下一個元素的位置:
正確使用方法      std::vector< int> Vec;
      std::vector< int>::iterator itVec;
      for( itVec = Vec.begin(); itVec != Vec.end(); )
      {
            if( WillDelete( *itVec) )
            {
                 itVec = Vec.erase( itVec);
            }
            else
               itList++;
      }
      
      注意:vector、deque 不能像上面的“正確使用方法2”的辦法來遍歷刪除。 


===========================================================================================

【http://www.jb51.net/article/41617.htm】

在使用 list、set 或 map遍歷刪除某些元素時可以這樣使用:

正確使用方法1

複製代碼代碼如下:

      std::list< int> List;
      std::list< int>::iterator itList;
      for( itList = List.begin(); itList != List.end(); )
      {
            if( WillDelete( *itList) )
            {
               itList = List.erase( itList);
            }
            else
               itList++;
      }

正確使用方法2  
複製代碼代碼如下:

    std::list< int> List;
      std::list< int>::iterator itList;
      for( itList = List.begin(); itList != List.end(); )
      {
            if( WillDelete( *itList) )
            {
               List.erase(itList++);
            }
            else
               itList++;
      }

正確使用方法3 
複製代碼代碼如下:

      std::list< int> List;
      std::list< int>::iterator it, next;
      for( it = List.begin(), next = it, next ++; it != List.end(); it = next, ++next)
      {
            if( WillDelete( *it) )
            {
               List.erase(it);
            }
      }

注:方法三更爲巧妙,但需注意方法三是用前需要判斷容器是否爲空,否則迭代器會出問題。

我測試得出,set.erase 不返回迭代器,list返回。
vector  刪除操作

複製代碼代碼如下:

std::vector <PACK_PRINT>::iterator It ; 
for(It=printItems.begin();It!=printItems.end();) 

  //我是說這裏怎麼判斷printItems printItems 裏PACK_PRINT.bh =0

  if( It.bh ==0) //是這樣嗎?
  {//刪除 
       It=printItems.erase(It); 
  } 
  else 
  {//不刪除 
       ++It; 
  } 
}


複製代碼代碼如下:

std::vector <PACK_PRINT> printItems;
int i = 0;
while(i < printItems.size())
{

          if(printItems[i].bh == 0)  //這裏比如我想把 printItems 時PACK_PRINT.bh =0 的刪除如何寫喲。另外這樣刪除有錯嗎?
          {//刪除
                printItems.erase(printItems.begin() + i);
          }
          else
          {//不刪除
                ++i;
          }
}


發佈了8 篇原創文章 · 獲贊 1 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章