std::map::erase的用法及陷阱

方法一:

  1. std::map<std::string, std::string > mapTest;  
  2. bool TestVal(const std::string & val);  
  3.   
  4. ......  
  5. std::map<std::string, std::string >::iterator it = mapTest.begin();  
  6. while(it != mapTest.end())  
  7. {  
  8.          if(TestVal(it->second))  
  9.          {  
  10.                  it = mapTest.erase(it);  
  11.          }  
  12.          else  
  13.                  it++;  
  14. }  
  15. ...........  
在這種方式中,通過std::map的erase方法在釋放了it後會返回指向下一個元素的指針來獲取最新的iterator


方法二:

  1. std::map<std::string, std::string > mapTest;  
  2. bool TestVal(const std::string & val);  
  3.   
  4. ......  
  5. std::map<std::string, std::string >::iterator it = mapTest.begin();  
  6. while(it != mapTest.end())  
  7. {  
  8.          if(TestVal(it->second))  
  9.          {  
  10.                 mapTest.erase(it++);  
  11.          }  
  12.          else  
  13.                  it++;  
  14. }  
  15. ...........  
該方法中利用了後++的特點,這個時候執行mapTest.erase(it++);這條語句分爲三個過程

1、先把it的值賦值給一個臨時變量做爲傳遞給erase的參數變量

2、因爲參數處理優先於函數調用,所以接下來執行了it++操作,也就是it現在已經指向了下一個地址。

3、再調用erase函數,釋放掉第一步中保存的要刪除的it的值的臨時變量所指的位置。


如果只是mapTest.erase(it); 當這條語句執行完後,it就是一個非法指針,如果再執行++就會出錯


總結,對於iter的移動在對erase時需要注意。


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”的辦法來遍歷刪除。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章