1. STL容器的遍历删除
  2. 今天在对截包程序的HashTable中加入计时机制时,碰到这个问题。对hash_map中的每个项加入时间后,用查询函数遍历hash_map,以删除掉那些在表存留时间比某个阈值长的表项(当然这个函数是应该运行在另起一个线程上的),但是在按照下面的方法对hash_map(用迭代器)遍历删除时,当找到第一个满足删除条件的元素并将其删除后,程序将提示非法:
  3. for(list<int>::iterator iter = m_map.begin(); iter != m_map.end(); ++iter) //这种做法是错误的
  4. {
  5. if(需要删除)
  6. {
  7. m_map.erase(iter);
  8. }
  9. }
  10.  
  11. 原因是当前节点已经被删除后,其使用的内存空间被释放的,那么再对已经删除的节点获得位置信息,这种访问当然就是非法的。
  12. 正确的做法是:
  13. for(list<int>::iterator iter = m_map.begin(); iter != m_map.end(); ) //这是正确的做法
  14. {
  15. if(需要删除)
  16. {
  17. m_map.erase(iter++);
  18. }
  19. else
  20. ++iter;
  21. }
  22.  
  23. 为什么呢?
  24.  
  25. map 是关联容器,由节点组成,每个节点都有自己独立的存储空间。除了包含元素对象之外,节点中还包含定位其前后相邻节点的位置信息(一般用指针表示),而且在 定位前、后节点(即对迭代器进行自减、自加运算)时都要根据当前节点中的位置信息进行计算。显然,如果此时当前节点已经被删除、其使用的内存空间被释放的 话,那么为了获得位置信息再对已经删除的节点进行访问就是非法的。
  26.  
  27. STL中对结点类容器(如list,hash_map)遍历时进行删除时,涉及到iterator的相关操作(以list为例):
  28. _Self& operator++()
  29. {
  30. this->_M_incr();
  31. return *this;
  32. }
  33. _Self operator++(int)
  34. { _Self __tmp = *this;
  35. this->_M_incr();
  36. return __tmp; //后缀++按照语意返回了++前的iterator,
  37. }
  38. void _M_incr() { _M_node = _M_node->_M_next; } //++的操作是使iterator的_M_node指向下一个结点
  39.  
  40. iterator erase(iterator __position)
  41. { _List_node_base* __next_node = __position._M_node->_M_next;
  42. _List_node_base* __prev_node = __position._M_node->_M_prev;
  43. _Node* __n = (_Node*) __position._M_node;
  44. __prev_node->_M_next = __next_node;
  45. __next_node->_M_prev = __prev_node;
  46. _STLP_STD::_Destroy(&__n->_M_data); //call T::~T()
  47. );
  48. return iterator((_Node*)__next_node);
  49.  
  50. }
  51. 分析代码我们可以看出,erase会释放掉__position_M_node, __position上再进行++是错误的。
  52. 所以不能在m_map.erase(iter)后,进行iter++。
  53.  
  54. 哪为什么m_map.erase(iter++)可以呢?为什么不能用m_map.erase(++iter)?
  55. 参照operator ++的代码我们可以找到答案。iter++返回了++之前的iter值,erase使用这个值能正确进行__position的前后结点的串接及删除正确 的结点,而++iter返回的是++之后的iter,所以m_map.erase(++iter)后串接不正确,iter->_M_node也是失 效的。
  56. 另外,对于非结点类,如数组类的容器vector,string,deque,如果erase会返回下个有效的iterator,可以这样处理:
  57.  
  58. for(vector<int>::iterator iter = m_vector.begin(); iter != m_vector.end();)
  59. {
  60. if(需要删除)
  61. {
  62. iter=m_vector.erase(iter);
  63. }
  64. else
  65. ++iter;
  66. }

STL容器的遍历删除的更多相关文章

  1. STL容器内数据删除

    STL中的容器按存储方式分为两类,一类是按以数组形式存储的容器(如:vector .deque):另一类是以不连续的节点形式存储的容器(如:list.set.map).在使用erase方法来删除元素时 ...

  2. stl map高效遍历删除的方法 [转]

    for(:iter!=mapStudent.end():) {      if((iter->second)>=aa)      {          //满足删除条件,删除当前结点,并指 ...

  3. stl map高效遍历删除的方法

    for(:iter!=mapStudent.end():) {      if((iter->second)>=aa)      {          //满足删除条件,删除当前结点,并指 ...

  4. STL容器迭代过程中删除元素技巧(转)

    1.连续内存序列容器(vector,string,deque) 序列容器的erase方法返回值是指向紧接在被删除元素之后的元素的有效迭代器,可以根据这个返回值来安全删除元素. vector<in ...

  5. c++ stl容器set成员函数介绍及set集合插入,遍历等用法举例

    c++ stl集合set介绍 c++ stl集合(Set)是一种包含已排序对象的关联容器.set/multiset会根据待定的排序准则,自动将元素排序.两者不同在于前者不允许元素重复,而后者允许. 1 ...

  6. STL中用erase()方法遍历删除元素 .xml

    pre{ line-height:1; color:#f0caa6; background-color:#2d161d; font-size:16px;}.sysFunc{color:#e54ae9; ...

  7. STL中用erase()方法遍历删除元素

    STL中的容器按存储方式分为两类,一类是按以数组形式存储的容器(如:vector .deque):另一类是以不连续的节点形式存储的容器(如:list.set.map).在使用erase方法来删除元素时 ...

  8. STL容器及算法题:删除奇数的QQ号

    最近思考到这样一个题目:在STL的set和vector容器里存储了1亿个QQ号,编写函数删除奇数QQ号. 1. STL容器简介 首先了解一下 set 和 vector 以及其他类似的 STL 容器: ...

  9. STL——遍历 删除 set 元素

    ==================================声明================================== 本文版权归作者所有. 本文原创,转载必须在正文中显要地注明 ...

随机推荐

  1. flex Chrome flash调试时 出现Shockwave flash has crashed的解决办法

    在Chrome中输入:chrome://plugins/     PPAPI的Flash Player停用. 使用NPAPI的Flash player. 这里好像没有显示是Debug版本. 但是我在调 ...

  2. CSRF攻击之原理讲解

    |=——————————————————————=| |=————–=[ CSRF攻击原理解析 ]=——————=| |=——————————————————————=| |=——————-=[ By ...

  3. CSS自定义文件上传按钮

    今天一同事问我文件上传按钮的问题,情况是这样的,他页面上有3个按钮,分为左中右三个,左边的位按钮甲,右边的位按钮乙,而中间的就是个文件选择按钮,情况大概是这个样子的: 两边的按钮都有了样式,但中间的选 ...

  4. PHP PDO_MYSQL 操作类 YAF嵌入高性能类而准备

    https://github.com/indieteq/PHP-MySQL-PDO-Database-Class PHP-PDO-MySQL-Class A PHP MySQL PDO class s ...

  5. JavaScript文件应该放在网页的什么位置

    JavaScript文件应该放在网页的什么位置 http://www.lihuai.net/qianduan/js/352.html 在<良好的JavaScript编程习惯>系列教程的第三 ...

  6. 如何在Windows7(IIS7)环境下安装 PHP

    一.安装IIS7 打开(1)[程序和功能],然后点击(2)[打开或关闭Windows功能] 勾选(1)[IIS管理控制台]和(2)CGI,然后点击[确定]按钮,等待安装完成.这个过程可能需要系统安装光 ...

  7. 使用git整体流程

    一.git提交代码走meger请求的整体流程 工作中使用git推代码时,如果走merge请求,那么也就是说拉代码时拉公共代码库的代码,但是提交时需要先提交到自己的代码库,然后在gitlab上提交mer ...

  8. Grub命令行

    今天电脑无缘无故无法正常启动,只提示 GRUB> 看来是GRUB引导出问题了,要解决下. 先 想到用制作U盘启动盘来启动,参照网上的方法,很简单用USBBOOT软件做了一个U盘启动盘,按F11在 ...

  9. iOS开发多线程--(NSOperation/Queue)

    iOS实现多线程的方式有三种,分别是NSThread.NSOperation.GCD. 关于GCD,请阅读GCD深入浅出学习 简介 NSOperation封装了需要执行的操作和执行操作所需的数据,提供 ...

  10. PHP-用ThinkPHP和Bootstrap实现用户登录设计

    一.目标 1.用ThinkPHP和Bootstrap实现用户登录设 2.初步界面如下 二.用到的工具及框架 1.ThinkPHP 2.Bootstrap 3.Subline 三.开发环境搭建 1.下载 ...