迭代器失效的幾種情況總結


大體內容來源:http://blog.csdn.net/lujiandong1/article/details/49872763

1.對於序列式容器:vector,queue等,序列式容器就是數組式容器,刪除當前的iterator會使得后邊所有元素的iterator都失效。這是因為其使用了連續分配的內存,闡述一個元素導致后面所有的元素都會向前移動一個位置,所以不能使用erase(iter++)的方式。但是erase方法可以返回下一個有效的iterator
  
for (iter = cont.begin(); iter != cont.end();)  
{  
   (*it)->doSomething();  
   if (shouldDelete(*iter))  
      iter = cont.erase(iter);  //erase刪除元素,返回下一個迭代器  
   else  
      ++iter;  
}  

迭代器失效的情況:

 

void vectorTest()  
{  
    vector<int> container;  
    for (int i = 0; i < 10; i++)  
    {  
        container.push_back(i);  
    }  
  
    vector<int>::iterator iter;  
     for (iter = container.begin(); iter != container.end(); iter++)  
    {  
            if (*iter > 3)  
              container.erase(iter);  
    }  
  
     for (iter = container.begin(); iter != container.end(); iter++)  
    {  
            cout<<*iter<<endl;  
    }  
}  

這段代碼在刪除后對迭代器自增,實際其本身已經失效了。  對於vector,刪除當前的iterator會使得用棉所有元素的iterator都失效,因為序列式容器內存是連續分配的,刪除一個元素導致后面所有的元素都會向前移動一個位置。

所以此時iter++指向的未知位置。正確的做法是向前面一樣的處理。

 

 

對於關聯式容器如(map,set,multimap,multiset),刪除當前的iterator,僅僅會使當前的iterator失效,只要在erase時,遞增當前iterator即可。這是因為map之類的容器,使用了紅黑樹來實現,插入、刪除一個節點不會對其他節點造成影響,erase迭代器只是被刪元素的迭代器失效,但是返回值為void,所以要采用erase(iter++)的方式刪除迭代器。

 

void mapTest()  
{  
    map<int, string> dataMap;  
  
  
    for (int i = 0; i < 100; i++)  
    {  
           string strValue = "Hello, World";  
  
            stringstream ss;  
            ss<<i;  
            string tmpStrCount;  
            ss>>tmpStrCount;  
            strValue += tmpStrCount;  
            dataMap.insert(make_pair(i, strValue));  
    }  
  
    cout<<"MAP元素內容為:"<<endl;  
     map<int, string>::iterator iter;  
    for (iter = dataMap.begin(); iter != dataMap.end(); iter++)  
    {  
            int nKey = iter->first;  
            string strValue = iter->second;  
            cout<<strValue<<endl;  
    }  
  
    cout<<"內容開始刪除:"<<endl;  
    /////////////////////////////////////////////擦除操作引發迭代器失效  
    for (iter = dataMap.begin(); iter != dataMap.end();iter++)  
    {  
            int nKey = iter->first;  
            string strValue = iter->second;  
  
           if (nKey % 2 == 0)  
           {  
                dataMap.erase(iter);  
  
           }  
           /* cout<<iter->second<<endl;*/  
    }  
}  

上述代碼會出現問題:dataMap.erase(iter)之后,iterator就已經失效了,所以iter無法自增,解決的辦法就是在其失效之前完成自增。

做出如下修改

 

for (iter = dataMap.begin(); iter != dataMap.end();)  
    {  
            int nKey = iter->first;  
            string strValue = iter->second;  
  
           if (nKey % 2 == 0)  
           {  
                dataMap.erase(iter++);  
                auto a = iter;  
  
           }  
           else {  
               iter ++;  
           }  
    }  

解析:dataMap.erase(iter++);這句話分幾步走,先把iter傳到erase里面,然后iter自增,然后再erase,所以iter在失效前已經自增了。

map是關聯式容器,以紅黑樹或者平衡二叉樹組織數據,雖然刪除了一個元素,整棵樹也會調整,以符合二叉樹或者紅黑樹的規范,但是單個節點的改變必然會調整樹的結構,其中單個節點在內存中的地址沒有變化且各個節點的指向關系。另外一種保險和比較易讀的寫法是寫一個臨時迭代器保存當前迭代器,之后迭代器本身自增,在erase臨時的

代碼如下:

 

if (nKey % 2 == 0)  
         {  
               map<int, string>::iterator tmpIter = iter;  
           iter++;  
               dataMap.erase(tmpIter);  
               //dataMap.erase(iter++) 這樣也行  
  
         }

 

總結:迭代器的失效分三種情況,分為數組形,鏈表性,樹形數據結構

數組形數據結構:該數據結構元素是分配在連續的內存中。

鏈表性數據結構:其也是用了不連續分配的內存

樹形數據結構:插入不會使得任何迭代器失效。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM