1. 程式人生 > >erase用法注意事項

erase用法注意事項

以前就發現了vector中的erase方法有些詭異(^_^),稍不注意,就會出錯。今天又一次遇到了,就索性總結一下,尤其是在迴圈體中用erase時,由於vector.begin() 和vector.end()是變化的,因此就引入了錯誤的可能性。

erase的函式原型有兩種形式:

iterator erase(iterator position);

iterator erase(iterator first, iterator last);

vector<int> veci;
veci.push_back(1);
veci.push_back(2);
veci.push_back(3);
veci.push_back(4);
veci.push_back(5);
veci.push_back(3);
veci.push_back(2);
veci.push_back(3);

for(vector<int>::iterator iter=veci.begin(); iter!=veci.end(); iter++)
{
      if( *iter == 3)
             veci.erase(iter);
}

乍一看這段程式碼,很正常。其實這裡面隱藏著一個很嚴重的錯誤:當veci.erase(iter)之後,iter就變成了一個野指標,對一個野指標進行 iter++ 是肯定會出錯的。

檢視MSDN,對於erase的返回值是這樣描述的:An iterator that designates the first element remaining beyond any elements removed, or a pointer to the end of the vector if no such element exists,於是改程式碼:

for(vector<int>::iterator iter=veci.begin(); iter!=veci.end(); iter++)
{
      if( *iter == 3)
             iter = veci.erase(iter);
}

這段程式碼也是錯誤的:1)無法刪除兩個連續的"3"; 2)當3位於vector最後位置的時候,也會出錯(在veci.end()上執行 ++ 操作)

正確的程式碼應該為:

for(vector<int>::iterator iter=veci.begin(); iter!=veci.end(); )
{
     if( *iter == 3)
          iter = veci.erase(iter);
      else
            iter ++ ;
}

為了避免對野指標進行操作,另一種解決方法如下:

vector<int>::iterator itor2;

for(vector<int>::iterator iter=veci.begin(); iter!=veci.end(); )
{
     if( *iter == 3)

     {   

           itor2=iter;
          veci.erase(itor2);
     }

      else
            iter ++ ;
}

要解決無法刪除兩個連續的3的另一種方法如下:

vector<int>  veci;

veci.erase(remove(veci.begin(),veci.end(),6),veci.end());

這裡用到了remove()函式,

注:remove是個stl的通用演算法std::remove(first,last,val)移除[first, last)範圍內等於val的元素在vector裡面用就類似於iter = std::remove(vec.begin(), vec.end(), val)但這個函式只是把val移到vec的末尾,並不真正刪除真正刪除還是要呼叫一次erase函式

**************************

簡介:這是STL中的容器的遍歷的使用方法的詳細頁面,介紹了和c/c++,C++ STL中的容器的遍歷的使用方法有關的知識,加入收藏請按鍵盤ctrl+D,謝謝大家的觀看!要檢視更多有關資訊,請點選此處

   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++;
      }