STL容器的遍历删除
STL容器的遍历删除
今天在对截包程序的HashTable中加入计时机制时,碰到这个问题。对hash_map中的每个项加入时间后,用查询函数遍历hash_map,以删除掉那些在表存留时间比某个阈值长的表项(当然这个函数是应该运行在另起一个线程上的),但是在按照下面的方法对hash_map(用迭代器)遍历删除时,当找到第一个满足删除条件的元素并将其删除后,程序将提示非法:
for(list<int>::iterator iter = m_map.begin(); iter != m_map.end(); ++iter) //这种做法是错误的
{
if(需要删除)
{
m_map.erase(iter);
}
}
原因是当前节点已经被删除后,其使用的内存空间被释放的,那么再对已经删除的节点获得位置信息,这种访问当然就是非法的。
正确的做法是:
for(list<int>::iterator iter = m_map.begin(); iter != m_map.end(); ) //这是正确的做法
{
if(需要删除)
{
m_map.erase(iter++);
}
else
++iter;
}
为什么呢?
map 是关联容器,由节点组成,每个节点都有自己独立的存储空间。除了包含元素对象之外,节点中还包含定位其前后相邻节点的位置信息(一般用指针表示),而且在 定位前、后节点(即对迭代器进行自减、自加运算)时都要根据当前节点中的位置信息进行计算。显然,如果此时当前节点已经被删除、其使用的内存空间被释放的 话,那么为了获得位置信息再对已经删除的节点进行访问就是非法的。
STL中对结点类容器(如list,hash_map)遍历时进行删除时,涉及到iterator的相关操作(以list为例):
_Self& operator++()
{
this->_M_incr();
return *this;
}
_Self operator++(int)
{ _Self __tmp = *this;
this->_M_incr();
return __tmp; //后缀++按照语意返回了++前的iterator,
}
void _M_incr() { _M_node = _M_node->_M_next; } //++的操作是使iterator的_M_node指向下一个结点
iterator erase(iterator __position)
{ _List_node_base* __next_node = __position._M_node->_M_next;
_List_node_base* __prev_node = __position._M_node->_M_prev;
_Node* __n = (_Node*) __position._M_node;
__prev_node->_M_next = __next_node;
__next_node->_M_prev = __prev_node;
_STLP_STD::_Destroy(&__n->_M_data); //call T::~T()
);
return iterator((_Node*)__next_node);
}
分析代码我们可以看出,erase会释放掉__position的_M_node, 在__position上再进行++是错误的。
所以不能在m_map.erase(iter)后,进行iter++。
哪为什么m_map.erase(iter++)可以呢?为什么不能用m_map.erase(++iter)?
参照operator ++的代码我们可以找到答案。iter++返回了++之前的iter值,erase使用这个值能正确进行__position的前后结点的串接及删除正确 的结点,而++iter返回的是++之后的iter,所以m_map.erase(++iter)后串接不正确,iter->_M_node也是失 效的。
另外,对于非结点类,如数组类的容器vector,string,deque,如果erase会返回下个有效的iterator,可以这样处理:
for(vector<int>::iterator iter = m_vector.begin(); iter != m_vector.end();)
{
if(需要删除)
{
iter=m_vector.erase(iter);
}
else
++iter;
}
STL容器的遍历删除的更多相关文章
- STL容器内数据删除
STL中的容器按存储方式分为两类,一类是按以数组形式存储的容器(如:vector .deque):另一类是以不连续的节点形式存储的容器(如:list.set.map).在使用erase方法来删除元素时 ...
- stl map高效遍历删除的方法 [转]
for(:iter!=mapStudent.end():) { if((iter->second)>=aa) { //满足删除条件,删除当前结点,并指 ...
- stl map高效遍历删除的方法
for(:iter!=mapStudent.end():) { if((iter->second)>=aa) { //满足删除条件,删除当前结点,并指 ...
- STL容器迭代过程中删除元素技巧(转)
1.连续内存序列容器(vector,string,deque) 序列容器的erase方法返回值是指向紧接在被删除元素之后的元素的有效迭代器,可以根据这个返回值来安全删除元素. vector<in ...
- c++ stl容器set成员函数介绍及set集合插入,遍历等用法举例
c++ stl集合set介绍 c++ stl集合(Set)是一种包含已排序对象的关联容器.set/multiset会根据待定的排序准则,自动将元素排序.两者不同在于前者不允许元素重复,而后者允许. 1 ...
- STL中用erase()方法遍历删除元素 .xml
pre{ line-height:1; color:#f0caa6; background-color:#2d161d; font-size:16px;}.sysFunc{color:#e54ae9; ...
- STL中用erase()方法遍历删除元素
STL中的容器按存储方式分为两类,一类是按以数组形式存储的容器(如:vector .deque):另一类是以不连续的节点形式存储的容器(如:list.set.map).在使用erase方法来删除元素时 ...
- STL容器及算法题:删除奇数的QQ号
最近思考到这样一个题目:在STL的set和vector容器里存储了1亿个QQ号,编写函数删除奇数QQ号. 1. STL容器简介 首先了解一下 set 和 vector 以及其他类似的 STL 容器: ...
- STL——遍历 删除 set 元素
==================================声明================================== 本文版权归作者所有. 本文原创,转载必须在正文中显要地注明 ...
随机推荐
- 笔直的水管 usaco 背包
背包dp入门,需要滚动数组: #include<iostream> #include<cstdio> #include<string> #include<cs ...
- Game shader or System shader is busy ::VS CSG
this error means The GPU is freezen Phyre::PSemaphoreOrbis::wait()//callstack something illegal in c ...
- 利用PE数据目录的导入表获取函数名及其地址
PE文件是以64字节的DOS文件头开始的(IMAGE_DOS_HEADER),接着是一段小DOS程序,然后是248字节的 NT文件头(IMAGE_NT_HEADERS),NT的文件头位置由IMAGE_ ...
- jQuery实现 浏览器后退到上次浏览位置
近日看腾讯.新浪的移动端网站,发现一件非常蛋疼的事情,在列表浏览内容,我往下翻,往下翻,突然,看到一个十分霸气的标题,于是点到文章查看详细内容,若干时间后,点回退按钮,浏览器回退到页面的最顶部了. 于 ...
- 还原TexturePacker plist 文件以及图片的方法 (切开各小图片)
原地址:http://blog.csdn.net/linuxchen/article/details/16865645 Python 脚本:(来自网络) unpack_plist.py 命令行: py ...
- 如何开发一个自己的 RubyGem?
「如何测试你的 RubyGem?」的前导文章 什么是 RubyGem RubyGem 是 Ruby 语言的标准源码打包格式. 大家一直都在用gem这个命令,但是很少有人知道这个东西是怎么来的,这里我从 ...
- Win7 VMWare 串口通信
下载安装工具: 1. 如果电脑(笔记本)没有串口接口,则需要使用一个 USB-Serial 转换线,这里使用 prolific usb-serial USB--串口转换线,首先需要在win7上安装对应 ...
- MYSQL 遭遇 THE TOTAL NUMBER OF LOCKS EXCEEDS THE LOCK TABLE SIZE
今天进行MySql 一个表数据的清理,经过漫长等待后出现 The total number of locks exceeds the lock table size 提示.以为是table_cache ...
- C# JSON字符串序列化与反序列化
JSON与c#对象转换http://hi.baidu.com/donick/item/4d741338870c91fe97f88d33 C# JSON字符串序列化与反序列化 – http://www. ...
- C#中对象的输出
假设有个Costmer类如下: class Costmer { public string Id { get; set; } public string City { get; set; } publ ...