先看如下一道改错题:

  1. #include<iostream>
  2. #include<vector>
  3. using namespace std;
  4.  
  5. void print(vector<int>);
  6.  
  7. int main()
  8. {
  9. vector<int> array;
  10. array.push_back(1);
  11. array.push_back(6);
  12. array.push_back(6);
  13. array.push_back(3);
  14. //删除array数组中所有的6
  15. vector<int>::iterator itor;
  16. vector<int>::iterator itor2;
  17. itor=array.begin();
  18.  
  19. for(itor=array.begin();itor!=array.end(); )
  20. {
  21. if(6==*itor)
  22. {
  23. itor2=itor;
  24. array.erase(itor2);
  25. }
  26. itor++;
  27. }
  28. print(array);
  29. return 0;
  30. }
  31. void print(vector<int> v)
  32. {
  33. cout<<"/n vector size is: "<<v.size()<<endl;
  34. vector<int>::iterator p = v.begin();
  35. }

答案解析:行itor=array.erase(itor);这句话后,itor不会移动,而只是把删除的数后面的数都往前移一位,所以删除了第一个6后,指针指向第2个6,然后在来个itor++,指针就指向array.end()了,给你画个草图:

修改如下即可:

  1. for(itor=array.begin(); itor!=array.end(); )
  2. {
  3. if(6==*itor)
  4. {
  5. itor2=itor;
  6. itor = array.erase(itor2);//消除后返回下一个迭代
  7. }
  8. else
  9. {
  10. itor++;
  11. }
  12. }

这仅仅是针对vector而言,其他容器又是怎样的呢?

erase()函数的功能是用来删除容器中的元素
删除某个容器里的某个元素:c.erase(T);
看似一个简单的动作,然而对不同类型的容器,内部却做了截然不同的事情,后面介绍。

假设有这样一个题目,将某个容器中所有满足条件N == X的元素删除,按照常规的思路应该有类似这样的代码:

  1. // 假设Container和container分别表示一种容器和对应的一个对象
  2. Container<T>::iterator it;
  3. for (it = container.begin(); it != container.end(); ++it)
  4. {
  5. if (N == X)
  6. container.erase(it);
  7. }

然而这样的代码对于任一种容器都是错误的

容器按内存分配方式可以分为链表容器和数组容器。
所谓的链表容器指的是一种表现方式,包括list、slist等这样基于节点的容器(动态分配内存块)和set、map、multiset、multimap等关联容器(平衡树实现),而数组容器指的是在一块连续的内存上保存元素的连续内存容器,比如vector、deque、string等。
链表容器以list为例,当执行container.erase(it)时,确实第一个满足条件的元素删除了,但这时it指针已经被删除了,它也不指向任何元素了,所以也只能到此为止了,也就是说上面的代码对于链表容器来说只能正确删除第一个满足条件的元素,针对这个问题我们首先想到的就是在删除指针之前,给其做个备份。
将这个临时变量直接建立在erase实现里,这样做更简洁,也显得专业些。

  1. list<int>::iterator it;
  2. for (it = lt.begin(); it != lt.end(); )
  3. {
  4. if (*it % 2 == 0)
  5. lt.erase(it++); //这里是关键
  6. else
  7. ++it;
  8. }

链表容器使用erase删除节点还有一个特点,就是会将下一个元素的地址返回,所以也可以这样实现:

  1. list<int>::iterator it;
  2. for (it = lt.begin(); it != lt.end(); )
  3. {
  4. if (*it % 2 == 0)
  5. it = lt.erase(it);//自动返回下一个元素的地址,不用再主动前移指针
  6. else
  7. ++it;
  8. }

数组容器以vector为例,当执行container.erase(it)时,和上面提到的一样,第一个满足条件的元素删除了,但这时数组容器不允许中间有“空隙”,所以会做个大动作,就是将被删元素后面所有的元素前移(参考STL源码),而数组容器记录的是下标,所以删除元素后,当前下标定位的元素也就顺理成章的变成了原有队列中的下一个元素,同样以删除偶数为例,代码如下:

  1. vector<int>::iterator it = v.begin();
  2. for (it = v.begin(); it != v.end(); )
  3. {
  4. if (*it % 2 == 0)
  5. v.erase(it);//删除元素后,后面元素自动往前移,不用挪动指
  6. else
  7. ++it;
  8. }

网上有说在VS2005里面上面的v.erase(it)写法是行的  VS2008及2010却运行会出现错误 会出现
vector erase iterator outside range  最保险的做法是将v.erase(it)改成 it=v.erase(it)

STL中erase的小心使用的更多相关文章

  1. C++ STL 中erase()的使用需要小心

    C++ STL极大的方便了用户编写程序,但是同时一不小心也会犯一些错误,如erase()造成迭代器失效经常会引起错误. 错误示例: std::list< int> List; std::l ...

  2. STL中erase()的用法

    erase()是STL提供的容器中比较常用的方法之一,它的功能是删除容器中的某些元素,其中它的函数原型如下: 1.有两个参数,且参数类型都是size_t型: string& erase ( s ...

  3. STL中erase()的陷阱

    最近在刷stl源码剖析这本书时,对于vector的erase()函数引起了我的注意 在删除单个元素时是这样定义的: iterator erase(iterator position){ !=end() ...

  4. STL中vector的赋值,遍历,查找,删除,自定义排序——sort,push_back,find,erase

    今天学习网络编程,那个程序中利用了STL中的sort,push_back,erase,自己没有接触过,今天学习一下,写了一个简单的学习程序.编译环境是VC6.0         这个程序使用了vect ...

  5. STL中list用法

    本文以List容器为例子,介绍了STL的基本内容,从容器到迭代器,再到普通函数,而且例子丰富,通俗易懂.不失为STL的入门文章,新手不容错过! 0 前言 1 定义一个list 2 使用list的成员函 ...

  6. C++ STL中哈希表Map 与 hash_map 介绍

    0 为什么需要hash_map 用过map吧?map提供一个很常用的功能,那就是提供key-value的存储和查找功能.例如,我要记录一个人名和相应的存储,而且随时增加,要快速查找和修改: 岳不群-华 ...

  7. STL容器 erase的使用陷井

    http://www.cppblog.com/beautykingdom/archive/2008/07/09/55760.aspx?opt=admin 在STL(标准模板库)中经常会碰到要删除容器中 ...

  8. STL 中的map 与 hash_map的理解

    可以参考侯捷编著的<STL源码剖析> STL 中的map 与 hash_map的理解 1.STL的map底层是用红黑树存储的,查找时间复杂度是log(n)级别: 2.STL的hash_ma ...

  9. STL中的map和hash_map

    以下全部copy于:http://blog.chinaunix.net/uid-26548237-id-3800125.html 在网上看到有关STL中hash_map的文章,以及一些其他关于STL ...

随机推荐

  1. Yum出错Error: Cannot find a valid baseurl for repo: base

    centos yum 错误 Error: Cannot find a valid baseurl for repo: addons 装了个CentOS 6.5,使用yum时出现了以下的错误提示. [r ...

  2. 怎样把HTC G7的内存扩展到2GB

    介绍 HTC G7的内部存储只有148M,两年前买它的时候,android应用大多比较小巧,148M已经足够用了.随着android版本的不断升级,应用变得越来越臃肿,G7也变得越来越吃力.就我个人而 ...

  3. linux权限及ntfs文件系统权限的知识

    关于ntfs权限的问题 文件的权限: [-dcbps][u:rwx][g:rwx][a:rwx] 当中: r=4, w=2, x=1,  u=owner, g=group, a=all user   ...

  4. DataGrid( 数据表格) 组件[4]

    本节课重点了解 EasyUI 中 DataGrid(数据表格)组件的使用方法,这个组件依赖于Panel(面板).Resizeable(调整大小).LinkButton(按钮).Pageination( ...

  5. IE浏览器下a标签嵌套img标签默认带有边框

    最近写在线主页时发现IE浏览器下a标签嵌套img标签默认带有边框: 解决办法:img{border:0 none;} 注意,严格意义上0和none都要加上!

  6. 掌众android面试题

    1,android动画分类? http://www.cnblogs.com/angeldevil/archive/2011/12/02/2271096.html 2,android service启动 ...

  7. Querylayer(查询图层) - 浅谈

    Querylayer(查询图层)是通过 SQL 查询定义的图层或独立表.通过 Querylayer 可将空间信息和非空间信息都存储在DBMS 中,从而使这些信息可以轻松地整合到 ArcMap 中的各 ...

  8. Ueditor使用方法

    1.到百度下载文件,有各种版本.下载.net版本 2.将所需文件导入工程中 分别是:themes文件夹.third-party文件夹.ueditor.all.min.js.ueditor.config ...

  9. OpenCV——识别手写体数字

    这个是树莓派上运行的, opencv3 opencv提供了一张手写数字图片给我们,如下图所示,可以作为识别手写数字的样本库. 0到9共十个数字,每个数字有五行,一行100个数字.首先要把这5000个数 ...

  10. 神经网络作业: NN LEARNING Coursera Machine Learning(Andrew Ng) WEEK 5

    在WEEK 5中,作业要求完成通过神经网络(NN)实现多分类的逻辑回归(MULTI-CLASS LOGISTIC REGRESSION)的监督学习(SUOERVISED LEARNING)来识别阿拉伯 ...