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 元素
==================================声明================================== 本文版权归作者所有. 本文原创,转载必须在正文中显要地注明 ...
随机推荐
- phonegap上传以及下载图片
在phonegap中,有时我们需要从服务器下载图片以及上传图片,这个时候可以用到官方提供的一个插件:FileTransfer 首先通过命令添加插件: cordova plugin add org.ap ...
- sql server 数据页缓冲区的内存瓶颈分析
查看数据库的计数器: SELECT * FROM sys.dm_os_performance_counters **也可以使用系统的性能计监测器查看. 右键图表-> 添加计数器. ...
- VC++之GetLastError()使用说明
VC中GetLastError()获取错误信息的使用 在VC中编写应用程序时,经常需要涉及到错误处理问题.许多函数调用只用TRUE和FALSE来表明函数的运行结果.一旦出现错误,MSDN中往往会指出请 ...
- *args和**kw魔法参数
学Python挺久了,现在才搞懂这个还是有点惭愧 *args:传入元组,无关键字 **kw:传入字典,有关键字 示例: *args **kw 一起使用时args的参数需在前:
- String、StringBuilder
public class testString{ public static void main(String[] args) { String a="cool"; String ...
- HDU 1393 Weird Clock (英语,纪念题)
这题简单,只要看懂题目就好,坑爹的是我的英语水平太差了,wa了n次,所以 仅此纪念 一下. //坑爹的英语题目,注意重点:move d times clockwise the current time ...
- (转)約瑟夫問題的兩個O(log n)解法
約瑟夫問題的兩個O(log n)解法 這個是學習編程時的一個耳熟能詳的問題了: n個人(編號爲0,1,...,n-1)圍成一個圈子,從0號開始依次報數,每數到第m個人,這個人就得自殺, 之後從下個人開 ...
- BZOJ 1143 1143: [CTSC2008]祭祀river 最长反链
1143: [CTSC2008]祭祀river Description 在遥远的东方,有一个神秘的民族,自称Y族.他们世代居住在水面上,奉龙王为神.每逢重大庆典, Y族都会在水面上举办盛大的祭祀活动. ...
- Windows 代码实现关机(直接黑屏)
整理资料的时候发现的以前的代码,本机Win7 x64 Sp1 运行直接关机,黑屏.就是利用RtlAdjustPrivilege函数提权,代码中的注释写的很详细了.用的VS2010写的,直接编译成x64 ...
- svn教程
安装过程: 1.下载软件后,双击程序进行安装,点击“Next”: 2.在许可证协议页面,选择“I Accept the terms in the License Agreement”,点击“Next” ...