先看如下一道改错题:

#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. 从MongoDB说起

    近日MongoDB宣布完成新一轮1.5亿美元融资,投资者包括EMC.Salesforce.com.英特尔.Red Hat以及Altimeter Capital等投资机构.作为当今最流行的NoSQL数据 ...

  2. 随记,C#修饰符访问级别

    private : 私有成员, 在类的内部才可以访问. protected : 保护成员,该类内部和继承类中可以访问. (无修饰符时默认)internal: 在同一命名空间内可以访问.public : ...

  3. CCArray(转)

    http://blog.csdn.net/passtome/article/details/7966451 CCArray也是cocos2d-x自己写的类.它相当于是objc的NSArray.在coc ...

  4. JavaScript学习(2)

    时间就像海绵里的水,要挤总还是有的,所以在最近不是太忙的时间里,我选择了挤时间,一点点的挤出了大把的时间,于是乎便迎来了我对javascript的第二阶段的学习,首先说下, 说起JavaScript大 ...

  5. NumberSpinner( 数字微调) 组件

    本节课重点了解 EasyUI 中 Spinner(微调)组件的使用方法,这个组件依赖于Numberbox(数值输入框)和 Spinner(微调)组件. 一. 加载方式//class 加载方式<i ...

  6. OD: Exploit Me - Overwrite Nearby Varible

    实验代码: #include<stdio.h> #include<string.h> #define PASSWORD "1234567" int veri ...

  7. Mindset + Know-how+Concepture + Methodology+Technology

    在做成都专案过程中深刻体会到一个IT全才应该具备Domain Know-how,拥有正确地理念是十分重要的, 我想只能是某几个领域,专案管理,专案运行中的各种手法,即Methodology,最后才是K ...

  8. Js遍历Josn对象(内容对比页实现思路)

    更好的遍历Josn的方法,利用jquery的each方法: var arr1 = [ "one", "two", "three", &quo ...

  9. asp.net 发送邮件代码 System.Net.Mail

    前台页面 SendEmail.aspx 代码 using System.Net.Mail;using System.Net; <h2> 发送电子邮件演示 </h2> <t ...

  10. 在eclipse中对于java的操作

    1. 新建project new project --> java project -->input the name of the project and choose the jre ...