当一个容器变化时,指向该容器中元素的迭代器可能失效。这使得在迭代器变化期间改变容器容易出现问题。在这方面,不同的容器提供不同的保障:
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. Thinkphp5 iis环境下安装报错400 500

    要求一:服务器需要开启伪静态功能 要求二:新建文件夹web.config 放到入口目录下(如public/web.config  或者/web.config),内容如: <?xml versio ...

  2. UNIX环境编程学习笔记(2)——文件I/O之不带缓冲的 I/O

    lienhua342014-08-25 1 文件描述符 对于内核而言,所有打开的文件都通过文件描述符引用.文件描述符是一个非负整数.当打开一个现有文件或创建一个新文件时,内核向进程返回一个文件描述符. ...

  3. JS中 try...catch...finally (转)

    JS的try..catch..finally var array = null; try { document.write(array[0]); } catch(err) { document.wri ...

  4. ABBYY FineReader 12中的用户模式你会用吗

    在ABBYY FineReader 12OCR文字识别软件中,有一个概念叫“训练”,它是在字符图像和字符本身之间建立对应关系的过程,训练模式可以提高含有装饰字体的文档或包含特殊字符(例如数学符号)文档 ...

  5. ubuntu下安装程序的五种方法

    在ubuntu当中,安装应用程序我所知道的有三种方法,分别是apt-get,dpkg安装deb和make install安装源码包三种.下面针对每一种方法各举例来说明. 一.apt-get方法 使用a ...

  6. 给你的 Golang 程序添加 GUI (使用 Electron )

    https://studygolang.com/articles/12065?fr=sidebar https://www.jianshu.com/p/a3be0d206d4c  另一种思路 推荐方式 ...

  7. [原]unity3d ios平台内存优化(一)

    关于内存优化,人云亦云 各有己见.本文将通过设置Strpping Level ,减少内存使用. 先看三幅图: 1.没做任何优化,默认选项 2.设置Stripping level 为 Use micro ...

  8. [Bayesian] “我是bayesian我怕谁”系列 - Exact Inference

    要整理这部分内容,一开始我是拒绝的.欣赏贝叶斯的人本就不多,这部分过后恐怕就要成为“从入门到放弃”系列. 但,这部分是基础,不管是Professor Daphne Koller,还是统计学习经典,都有 ...

  9. aspose导出excel文件

    using Aspose.Cells; using System; using System.Collections.Generic; using System.Data; using System. ...

  10. 让树莓派自动上报IP地址到邮箱,二代B

    由于我使用树莓派的场景大多数是在没有显示器.只用terminal连接它的情况下,所以,它的IP地址有时会在重启之后变掉(DHCP的),导致我无法通过terminal连接上它.然后我又要很麻烦地登录路由 ...