先看如下一道改错题:

#include<iostream>
#include<vector>
using namespace std; void print(vector<int>); int main()
{
vector<int> array;
array.push_back(1);
array.push_back(6);
array.push_back(6);
array.push_back(3);
//删除array数组中所有的6
vector<int>::iterator itor;
vector<int>::iterator itor2;
itor=array.begin(); for(itor=array.begin();itor!=array.end(); )
{
if(6==*itor)
{
itor2=itor;
array.erase(itor2);
}
itor++;
}
print(array);
return 0;
}
void print(vector<int> v)
{
cout<<"/n vector size is: "<<v.size()<<endl;
vector<int>::iterator p = v.begin();
}

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

修改如下即可:

for(itor=array.begin();   itor!=array.end();   )
{
if(6==*itor)
{
itor2=itor;
itor = array.erase(itor2);//消除后返回下一个迭代
}
else
{
itor++;
}
}

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

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

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

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

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

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

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

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

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

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

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

网上有说在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. JDBC编程之事务处理

    JDBC中的事务处理指的是事务的一致性等问题,例如插入一条数据(id,name,password)到表中,另一条数据(address,id)到另一张表中,并且两条数据是相关联的,那么假设第一条数据插入 ...

  2. MongoDB Connector for Hadoop

    MongoDB Connector for Hadoop https://github.com/mongodb/mongo-hadoop Purpose The MongoDB Connector f ...

  3. UVAlive 6131 dp+斜率优化

    这道题和06年论文<从一类单调性问题看算法的优化>第一道例题很相似. 题意:给出n个矿的重量和位置,这些矿石只能从上往下运送,现在要在这些地方建造m个heap,要使得,sigma距离*重量 ...

  4. Ajax原生XHR对象

    前端学了有一段时间了,在项目中我通常使用的都是jQuery封装好的Ajax函数($.ajax.$.get.$.post),使用非常的简单方便,但为了更清楚的了解Ajax,需要学习原生xhr对象.   ...

  5. ReportViewer导出功能筛选

    ReportViewer只能导出Excel,把导出Word和PDF功能去掉 <rsweb:ReportViewer ID="ReportViewer1" runat=&quo ...

  6. Map Resource Definition 中type为 'ArcGIS Server Local'.

    在使用 MapResourceManager, Map进行 地图显示 时, 在 Map Resource Definition 的 type 为 ArcGIS Server Local时概述. 1,打 ...

  7. 基于java callable及future接口解决生产者消费者问题

    这两天复习java线程时,把java里面的线程基本知识点与jdk1.5以后新添加的一些类的使用都了解了一下,借用生产者消费者的问题来将他们实践一下. 题目:(题目在csdn一大牛的空间找的) 生产者- ...

  8. UIViewController的生命周期(图解)

    当一个视图控制器被创建,并在屏幕上显示的时候. 代码的执行顺序1. alloc                             创建对象,分配空间2.init (initWithNibName ...

  9. javascript使用for循环批量注册的事件不能正确获取索引值的解决方法

    今天遇到一个问题,那就是当使用for循环批量注册事件处理函数,然后最后通过事件处理函数获取当前元素的索引值的时候会失败,先看一段代码实例: <script type="text/jav ...

  10. POJ3111 K Best(另类背包+二分+变态精度)

    POJ3111 K Best,看讨论区说数据有点变态,精度要求较高,我就直接把循环写成了100次,6100ms过,(试了一下30,40都会wa,50是4000ms) 第一次在POJ上看到下面这种东西还 ...