STL中迭代器失效问题

来源:互联网 发布:2016gdp排名 知乎 编辑:程序博客网 时间:2024/05/21 18:49

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时记得后置递增它;

0 0
原创粉丝点击