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 元素
==================================声明================================== 本文版权归作者所有. 本文原创,转载必须在正文中显要地注明 ...
随机推荐
- Java获取项目中的路径 分类: Java Game 2014-08-14 10:17 122人阅读 评论(0) 收藏
在项目中经常需要获取某个文件的路径: 在这里提供一些获取路径的方法.. 1.此种方式获取的路径,是当前类所在的路径: UserDAOTest.class.getResource("UserD ...
- EXCEL 跨表比较数据
Public Sub Compare(fullname As String, sheet As String) Dim conn, sql, rows, i, cellContents ,rowInd ...
- TJU 4087. box
题目:Tuhao and his two small partners participated in the tournament.But in the end, they lost the cha ...
- 一个有趣的Ajax Hack示范
今天在梦之光芒的BLOG上看见了一个Ajax Hack示范,其实跨站发现很容易,但是要做到大危害还是很难,偷偷COOKIE什么的只针对用户而已,XSS WORM的那种利用才是可怕的. 来看看他的一段V ...
- javascript实现数据结构与算法系列:队列 -- 链队列和循环队列实现及示例
1 队列的基本概念 队列(Queue):也是运算受限的线性表.是一种先进先出(First In First Out ,简称FIFO)的线性表.只允许在表的一端进行插入,而在另一端进行删除. 队首(fr ...
- Sqli-labs less 28a
Less-28a 本关与28基本一致,只是过滤条件少了几个. http://127.0.0.1/sqllib/Less-28a/?id=100%27)unIon%0bsElect%0b1,@@base ...
- chapter 2
1.分片:序列变量,字符串,列表,元组,集合..都可以使用分片来访问指定的数据项,分片三种方式:seq[]访问某个数据项,seq[-1]表示访问序列最后一个数据项,seq[-2]倒数第二个数据项. s ...
- IDEA开发spark本地运行
1.建立spakTesk项目,建立scala对象Test 2.Tesk对象的代码如下 package sparkTest /** * Created by jiahong on 15-8-2. */ ...
- java 反射创建对象并传入参数
/* * 通过反射创建带参数的对象 */ public Object Creatobject(String ClassPath, Object[] Params) throws Exception { ...
- hdu 4023 Game 博弈论
思路: 将15种分成5类: 1.1和2为一类: 2.3,4,5,6为一类: 3.7,8,9,10为一类: 4.11,12,13,14,15为一类: 5.15为一类. 比较各类的优先级,就会发现放置的顺 ...