当一个容器变化时,指向该容器中元素的迭代器可能失效。这使得在迭代器变化期间改变容器容易出现问题。在这方面,不同的容器提供不同的保障:
vectors: 引起内存重新分配的插入运算使所有迭代器失效,插入也使得插入位置及其后位置的迭代器失效,删除运算使得删除位置及其后位置的迭代器失效.
vector的push_back操作可能没事,但是一旦引发内存重分配,所有迭代器都会失效;
vector的insert操作插入点之后的所有迭代器失效;但一旦引发内存重分配,所有迭代器都会失效;
vector的erase操作插入点之后的所有迭代器失效;
vector的reserve操作所有迭代器失效(因为它导致内存重分配);

list/map: 插入不会使得任何迭代器失效;删除运算使指向删除位置的迭代器失效,但是不会失效其他迭代器.
deque的insert操作所有迭代器失效;
deque的erase操作所有迭代器失效;

1. 对于关联容器(如map, set, multimap,multiset),删除当前的iterator,仅仅会使当前的iterator失效,只要在erase时,递增当前iterator即可。这是因为map之类的容器,使用了红黑树来实现,插入、删除一个结点不会对其他结点造成影响。erase迭代器只是被删元素的迭代器失效,但是返回值为void,所以要采用erase(iter++)的方式删除迭代器。
for (iter = cont.begin(); it != cont.end();)
{
   (*iter)->doSomething();
   if (shouldDelete(*iter))
      cont.erase(iter++);
   else
      ++iter;
}

2. 对于序列式容器(如vector,deque),删除当前的iterator会使后面所有元素的iterator都失效。这是因为vetor,deque使用了连续分配的内存,删除一个元素导致后面所有的元素会向前移动一个位置。所以不能使用erase(iter++)的方式,还好erase方法可以返回下一个有效的iterator。
for (iter = cont.begin(); iter != cont.end();)
{
   (*it)->doSomething();
   if (shouldDelete(*iter))
      iter = cont.erase(iter); 
   else
      ++iter;
}
3. 对于list来说,它使用了不连续分配的内存,并且它的erase方法也会返回下一个有效的iterator,因此上面两种方法都可以使用。

删除数组中某个元素后连续重复的元素,例如 1,1,2,3,3,1,1,1,4,0 ---> 1, 2,3,1,4,0。给出问题的一个正确的实现:

  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4. int main(int argc, char* argv[])
  5. {
  6. int a[] = {1, 1, 3, 3, 3, 2, 4, 1, 1, 1, 0};
  7. int size = sizeof(a)/sizeof(a[0]);
  8. vector<int> vec(a, a+size);
  9. vector<int>::iterator iter = vec.begin();
  10. int previous = *iter;
  11. ++iter;
  12. for (; iter != vec.end();)
  13. {
  14. if(*iter == previous)
  15. {
  16. iter = vec.erase(iter);
  17. }
  18. else
  19. {
  20. previous = *iter;
  21. ++iter;
  22. }
  23. }
  24. for(iter = vec.begin(); iter != vec.end(); ++iter)
  25. {
  26. cout << *iter << endl;
  27. }
  28. return 0;
  29. }

PS. 不过实际上这个问题,用vector来实现不是很适合,因为每次删除一个元素,都会引起vector的一个resize操作。resize的时间复杂度是O(n),整个的resize操作要花费O(n^2)。最好是选择list最为容器,list最适合那些需要在容器中间做插入、删除的例子。

【转】失效迭代器(Invalidating Iterators)的更多相关文章

  1. C++ 标准模板库(STL)——迭代器(iterators)的用法及理解

    C++ STL中迭代器(iterators)用于遍历对象集合的元素.由于容器大小随着插入删除等操作动态改变,无法像静态数组那样获取数组长度然后遍历容器里的所有元素:这时就需要迭代器,每次从容器内第一个 ...

  2. C++ STL中迭代器失效的问题

    my_container.erase(iter); 其中my_container是STL的某种容器,iter是指向这个容器中某个元素的迭代器.如果不是在for,while循环中,这种方式删除元素没有问 ...

  3. C++中迭代器原理、失效和简单实现

    目录 迭代器的使用 迭代器的种类 迭代器的失效 迭代器的实现 1.迭代器的使用 为了提高C++编程的效率,STL中提供了许多容器,包括vector.list.map.set等.有些容器例如vector ...

  4. 模拟实现简化版List迭代器&嵌入List

    1.迭代器(iterators)概念(1)迭代器是一种抽象的设计概念,其定义为:提供一种方法,使他能够按顺序遍历某个聚合体(容器)所包含的所有元素,但又不需要暴露该容器的内部表现方式. (2)迭代器是 ...

  5. 【OpenMesh】使用迭代器和循环机

    原文出处: http://openmesh.org/Documentation/OpenMesh-Doc-Latest/tutorial.html 这个例子展现: 如何使用迭代器 如何使用循环机 这个 ...

  6. python的迭代器、生成器、装饰器

    迭代器.生成器.装饰器 在这个实验里我们学习迭代器.生成器.装饰器有关知识. 知识点 迭代器 生成器 生成器表达式 闭包 装饰器 实验步骤 1. 迭代器 Python 迭代器(Iterators)对象 ...

  7. STL迭代器------Traits编程技法详细理解(一)

    最近在看STL源码解析的迭代器(iterators)一章,涉及到c++ Traits的编程技法,刚开始看时一头雾水,反复看了好几遍之后才理解这个东西,因此来写写在这方面的理解,如有错误,希望读者指正. ...

  8. 容器vector 迭代器iterator 应用

    #include <iostream> #include <vector> using namespace std; int main() { vector<int> ...

  9. Qt容器类之二:迭代器

    一.介绍 遍历一个容器可以使用迭代器(iterators)来完成,迭代器提供了一个统一的方法来访问容器中的项目.Qt的容器类提供了两种类型的迭代器:Java风格迭代器和STL风格迭代器.如果只是想按顺 ...

随机推荐

  1. SOAP消息头的处理

    SOAP消息头的处理 WebService学习总结(四)——调用第三方提供的webService服务 SOAP中 RPC/ENC 为啥被抛弃

  2. 机器学习结果加ID插入数据库源码

    import org.apache.spark.mllib.evaluation.BinaryClassificationMetrics import org.apache.spark.mllib.l ...

  3. 微信小程序/支付宝小程序 WxParse解析富文本(html)代码

    小程序本身并不太支持html代码,比如html的img.span.p这个时候改这么办呢?需要用到一个小插件WxParse来实现. 小程序高级交流群:336925436  微信小程序支持富文本编辑器代码 ...

  4. fopen flock fclose 文件用法

    fopen函数是用来打开文件或者连接 若成功,则返回 true.若失败,则返回 false. fopen打开连接是不能直接输出的 使用: <?php $file = fopen("te ...

  5. Android开发中常用的库总结(持续更新)

    这篇文章用来收集Android开发中常用的库,都是实际使用过的.持续更新... 1.消息提示的小红点 微信,微博消息提示的小红点. 开源库地址:https://github.com/stefanjau ...

  6. php下webservice使用总结

    基于thinkphp3.2的 1.修改php配置 php.ini extension=php_soap.dll soap.wsdl_cache_enabled=0 2.soap有两种模式 wsdl和 ...

  7. oracle数据库中sql%notfound的用法

    SQL%NOTFOUND 是一个布尔值.与最近的sql语句(update,insert,delete,select)发生交互,当最近的一条sql语句没有涉及任何行的时候,则返回true.否则返回fal ...

  8. centos 中文乱码解决途径

    在使用CentOS系统时,安装的时候可能你会遇到英文的CentOS系统,在这中情况下安装CentOS系统时是默认安装(即英文).安装完毕后,出现的各种中文乱码.那么,我们如何解决这种问题呢. 一.Ce ...

  9. Linux+Redis实战教程_day02_Linux系统上安装MySQL

    Linux系统上安装MySQL 安装MySQL 卸载自带mysql 查询mysql的安装情况,可以直接使用了 rpm -qa | grep -i mysql –-color 卸载原生的MySQL rp ...

  10. C++ 默认构造函数小记

    #include <string> #include <map> using namespace std; class A { public: A(string name):n ...