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

大致內容來源: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都失效,由於序列式容器內存是連續分配的,刪除一個元素致使後面全部的元素都會向前移動一個位置。spa

因此此時iter++指向的未知位置。正確的作法是向前面同樣的處理。.net

 

 

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

 

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沒法自增,解決的辦法就是在其失效以前完成自增。blog

作出以下修改內存

 

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在失效前已經自增了。string

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

代碼以下:class

 

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

 

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

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

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

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

相關文章
相關標籤/搜索