STL中迭代器失效問題

1)vector erase造成迭代器失效

 erase成員函數,它刪除了迭代器指向的元素,並且返回要被刪除的元素之後的迭代器。


#include <vector>
#include <list>
using namespace std;

 

int _tmain(int argc, _TCHAR* argv[])
{
 std::vector<int>  my_container; 

 for (int i = 0; i < 10; ++i) 
 {  
  my_container.push_back(i);  
 } 

 std::vector<int>::iterator it;

 for (it=my_container.begin();it!= my_container.end(); ) 
 {  
  if (*it % 2 == 1) 
  {  
   my_container.erase(it);  
  }else
  {
   it++;
  }
 } 

 for (vector<int>::iterator iter=my_container.begin();iter!=my_container.end();iter++)
 {
  //
  printf("value=%d\n",*iter);

 }

 return 0;
}

 

上面程序當刪掉第一個奇數時,迭代器my_container.end()已經失效,it和my_container.end()比較時造成程序崩潰;

但是改爲:it=my_container.erase(it);  程序不崩潰了,why?

 

針對vector容器,失效情況還有:

1.當插入(push_back)一個元素後,end操作返回的迭代器肯定失效。
2.當插入(push_back)一個元素後,capacity返回值與沒有插入元素之前相比有改變,則需要重新加載整個容器,此時first和end操作返回的迭代器都會失效。
3.當進行刪除操作(erase,pop_back)後,指向刪除點的迭代器全部失效;指向刪除點後面的元素的迭代器也將全部失效。

 

2)List容器失效情況

將上面的例子改成list,代碼如下:

#include <vector>
#include <list>
using namespace std;

bool isOdd(int value)  
{  
 return (value % 2) == 1;  

int _tmain(int argc, _TCHAR* argv[])
{
 std::list<int>  my_container; 

 for (int i = 0; i < 10; ++i) 
 {  
  my_container.push_back(i);  
 } 


 std::list<int>::iterator it;

 for (it=my_container.begin();it!= my_container.end(); ) 
 {  
  if (*it % 2 == 1) 
  {  
   my_container.erase(it); 

  }else
  {
   it++;
  }

  std::list<int>::iterator iter1=my_container.end();

 } 

 for (list<int>::iterator iter=my_container.begin();iter!=my_container.end();iter++)
 {
  //
  printf("value1=%d\n",*iter);

 }

 return 0;
}

 

程序還是崩潰,原因刪除第一個奇數後,指向該刪除節點的迭代器失效,後面用一個失效的迭代器和my_container.end()作比較,造成程序崩潰,該程序只要將

 my_container.erase(it); 

改爲:

 it=my_container.erase(it); 

就ok了。erase的返回值指向被刪元素後的迭代器;

 

或者改爲:

 my_container.erase(it++); 

也ok;

 

注意:

List/set/map
1.刪除時,指向該刪除節點的迭代器失效

 

3)deque 容器失效--摘自c++ primer

deque迭代器的失效情況:
1.在deque容器首部或者尾部插入元素不會使得任何迭代器失效。
2.在其首部或尾部刪除元素則只會使指向被刪除元素的迭代器失效。
3.在deque容器的任何其他位置的插入和刪除操作將使指向該容器元素的所有迭代器失效。


 規則:

兩條規制:
1、對於節點式容器(map, list, set)元素的刪除,插入操作會導致指向該元素的迭代器失效,其他元素迭代器不受影響。
2、對於順序式容器(vector)元素的刪除、插入操作會導致指向該元素以及後面的元素的迭代器失效。

3)衆所周之當使用一個容器的insert或者erase函數通過迭代器插入或刪除元素"可能"會導致迭代器失效,因此很多建議都是讓我們獲取insert或者erase返回的迭代器,以便用重新獲取新的有效的迭代器進行正確的操作;就像例子中的it=my_container.erase(it); 

4)可以使用容器的remove或remove_if函數代替erase;



 (4)Map erase 失效情況參考:

http://blog.csdn.net/smilestone_322/article/details/7976764

 

(5)pop_front 只有list和deque纔有;

 

總結:

1)刪除一個容器中有特定值的所有對象:

1.1)如果容器是vector、string或deque,使用erase-remove慣用法;

1.2)如果容器是list,使用list::remove;

1.3)如果容器是標準關聯容器,使用它的erase成員函數;

 

2)刪除一個容器中滿足一個特定判定式的所有對象:

2.1)如果容器是vector、string或deque,使用erase-remove_if慣用法;

2.2)如果容器是list,使用list::remove_if;

2.3)如果容器是標準關聯容器,使用remove_copy_if和swap,或寫一個循環來遍歷容器元素,當你把迭代
器傳給erase時記得後置遞增它;

 

3)在循環內做某些事情(除了刪除對象之外)

3.1)如果容器是標準序列容器,寫一個循環來遍歷容器元素,每當調用erase時記得都用它的返回值更新你的迭代器;

3.2)如果容器是標準關聯容器,寫一個循環來遍歷容器元素,當你把迭代器傳給erase時記得後置遞增它;

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