VC驿站

 找回密码
 加入驿站

QQ登录

只需一步,快速开始

有编程疑问吗?还请到提问专区发帖提问!
搜索
查看: 1140|回复: 11

[交流] STL中各容器的erase()方法遍历删除元素

[复制链接]
51_avatar_middle
online_admins Syc 发表于 2017-12-7 15:31:42 | 显示全部楼层 |阅读模式
最近一段时间做公司的一个服务器端游戏项目,因为要做到跨平台,所以虽然编译器用的是 vs2013,但基本用的都是C++标准的东西,这样方便以后再各个平台间移植。用到C++标准的东西,自然C++的标准模板库STL是不能少了,用到了里面的好几个容器,比如:vector、list、map、dqueue 等等。

关于这几个容器的时候这里面我就不做过多描述了,期间有一个非常值得大家注意的问题。我们知道遍历一个容器可以用迭代器,删除容器中第一个元素可以用 erase 方法,如果这两个操作单独分开来做确实没什么问题,也没什么好说的。可如果这两个操作是在一起呢?也就是说做的操作是遍历删除,那么就有一些要注意的事项了。

例如有如下代码:
  1. int main()
  2. {
  3.     vector<int> a = {12, 23, 34, 45, 56, 67, 78, 89};
  4.      
  5.     for (auto iter = a.begin(); iter != a.end(); ++iter) {
  6.         if (*iter > 30) {
  7.             a.erase(iter);
  8.                 }
  9. }
复制代码


乍一看好像没什么问题,但其实有很大的问题。本身执行完这句话之后:a.erase(iter); 是成功的将当前的元素给删除了,但是删除完之后此时的 iter 迭代器已经是一个被删除元素的了,所以之后再对他进行 ++iter的操作或者其他任何操作的结果都是未知的。所以之后的循环遍历肯定有很大的问题。那么正确的应该怎么来做呢?

通过查找相关资料,我们找到了关于 vector 的 erase 函数返回值的相关说明:
Return value
An iterator pointing to the new location of the element that followed the last element erased by the function call. This is the container end if the operation erased the last element in the sequence.

Member type iterator is a random access iterator type that points to elements.

大家看到了吧,也就是说 erase 的返回值是指向当前被删除元素的下一个元素的迭代器了,所以正确的写法应该是这样:
  1. iter = a.erase(iter);
复制代码


大家不妨试试!

分析过程说完了之后,下面找到了一片不错的文章介绍了 STL 中的 list、set、map、vector、deque 等容器的遍历删除都应该怎么操作,我给大家转载过来,希望对大家有帮助!

先总结一下(回复后可见):
list、set、map 容器的遍历删除:两种办法:
游客,如果您要查看本帖隐藏内容请回复


vector、deque 容器的遍历删除:一种办法:
游客,如果您要查看本帖隐藏内容请回复


以下为转载的文章:

STL中的容器按存储方式分为两类,一类是按以数组形式存储的容器(如:vector 、deque);另一类是以不连续的节点形式存储的容器(如:list、set、map)。在使用erase方法来删除元素时,需要注意一些问题。
      在使用 list、set 或 map遍历删除某些元素时可以这样使用:

正确使用方法1:
  1.       std::list< int> List;
  2.       std::list< int>::iterator itList;
  3.       for( itList = List.begin(); itList != List.end(); )
  4.       {
  5.             if( WillDelete( *itList) )
  6.             {
  7.                itList = List.erase( itList);
  8.             }
  9.             else
  10.                itList++;
  11.       }
复制代码


正确使用方法2:
  1.       std::list< int> List;
  2.       std::list< int>::iterator itList;
  3.       for( itList = List.begin(); itList != List.end(); )
  4.       {
  5.             if( WillDelete( *itList) )
  6.             {
  7.                List.erase( itList++);
  8.             }
  9.             else
  10.                itList++;
  11.       }
复制代码


下面是两个错误的使用方法:

错误使用方法1:
  1.       std::list< int> List;
  2.       std::list< int>::iterator itList;
  3.       for( itList = List.begin(); itList != List.end(); itList++)
  4.       {
  5.             if( WillDelete( *itList) )
  6.             {
  7.                List.erase( itList);
  8.             }
  9.       }
复制代码


错误使用方法2:
  1.       std::list< int> List;
  2.       std::list< int>::iterator itList;
  3.       for( itList = List.begin(); itList != List.end(); )
  4.       {
  5.             if( WillDelete( *itList) )
  6.             {
  7.                itList = List.erase( ++itList);
  8.             }
  9.             else
  10.                itList++;
  11.       }
复制代码


      正确使用方法1:通过erase方法的返回值来获取下一个元素的位置
      正确使用方法2:在调用erase方法之前先使用 “++”来获取下一个元素的位置
      错误使用方法1:在调用erase方法之后使用“++”来获取下一个元素的位置,由于在调用erase方法以后,该元素的位置已经被删除,如果在根据这个旧的位置来获取下一个位置,则会出现异常。
      错误使用方法2:同上。

      这里“++”运算符与我们平常的理解刚好相反,erase( itList++) 是先获取下一个元素的位置在删除; erase( ++itList) 是删除以后再获取下一个元素的位置。

     在使用 vector、deque遍历删除元素时,也可以通过erase的返回值来获取下一个元素的位置:

正确使用方法:
  1.       std::vector< int> Vec;
  2.       std::vector< int>::iterator itVec;
  3.       for( itVec = Vec.begin(); itVec != Vec.end(); )
  4.       {
  5.             if( WillDelete( *itVec) )
  6.             {
  7.                  itVec = Vec.erase( itVec);
  8.             }
  9.             else
  10.                itList++;
  11.       }
复制代码


注意:vector、deque 不能像上面的“正确使用方法2”的办法来遍历删除。




上一篇:boost regex 匹配的问题
下一篇:C++中的 atoi 和 itoa

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你已经在论坛发帖求助,并且从坛友或者管理的回复中解决了问题,请编辑帖子并把分类改成【已解决】

如何回报帮助你解决问题的坛友?可以给对方加【热心】【驿站币】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

74_avatar_middle
在线会员 zuiwuchang 发表于 2017-12-7 15:53:49 | 显示全部楼层
look   

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你已经在论坛发帖求助,并且从坛友或者管理的回复中解决了问题,请编辑帖子并把分类改成【已解决】

如何回报帮助你解决问题的坛友?可以给对方加【热心】【驿站币】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复 支持 反对

使用道具 举报

10_avatar_middle
在线会员 any5429 发表于 2017-12-7 16:23:16 | 显示全部楼层
我看看跟我的一样不

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你已经在论坛发帖求助,并且从坛友或者管理的回复中解决了问题,请编辑帖子并把分类改成【已解决】

如何回报帮助你解决问题的坛友?可以给对方加【热心】【驿站币】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复 支持 反对

使用道具 举报

50_avatar_middle
在线会员 x13186705301 发表于 2017-12-8 09:09:21 | 显示全部楼层
学习学习

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你已经在论坛发帖求助,并且从坛友或者管理的回复中解决了问题,请编辑帖子并把分类改成【已解决】

如何回报帮助你解决问题的坛友?可以给对方加【热心】【驿站币】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复 支持 反对

使用道具 举报

14_avatar_middle
在线会员 lin19900801 发表于 2018-1-16 12:36:28 | 显示全部楼层
嗯,这个可以有,学习排坑的好文章

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你已经在论坛发帖求助,并且从坛友或者管理的回复中解决了问题,请编辑帖子并把分类改成【已解决】

如何回报帮助你解决问题的坛友?可以给对方加【热心】【驿站币】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复 支持 反对

使用道具 举报

83_avatar_middle
在线会员 wwh944116 发表于 2018-2-6 01:21:23 | 显示全部楼层
支持并学习一下.

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你已经在论坛发帖求助,并且从坛友或者管理的回复中解决了问题,请编辑帖子并把分类改成【已解决】

如何回报帮助你解决问题的坛友?可以给对方加【热心】【驿站币】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复 支持 反对

使用道具 举报

77_avatar_middle
在线会员 ct201804 发表于 2018-4-5 13:47:00 | 显示全部楼层
学习了 。。。。 STL中各容器的erase()方法遍历删除元素

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你已经在论坛发帖求助,并且从坛友或者管理的回复中解决了问题,请编辑帖子并把分类改成【已解决】

如何回报帮助你解决问题的坛友?可以给对方加【热心】【驿站币】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复 支持 反对

使用道具 举报

87_avatar_middle
在线会员 xiaotao701 发表于 2018-5-22 21:42:24 | 显示全部楼层
PXSTR pszBuffer = GetBuffer( nLength );

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你已经在论坛发帖求助,并且从坛友或者管理的回复中解决了问题,请编辑帖子并把分类改成【已解决】

如何回报帮助你解决问题的坛友?可以给对方加【热心】【驿站币】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复 支持 反对

使用道具 举报

74_avatar_middle
在线会员 jiaokai123 发表于 2018-6-27 16:13:21 | 显示全部楼层
精品 学习。

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你已经在论坛发帖求助,并且从坛友或者管理的回复中解决了问题,请编辑帖子并把分类改成【已解决】

如何回报帮助你解决问题的坛友?可以给对方加【热心】【驿站币】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复 支持 反对

使用道具 举报

05_avatar_middle
在线会员 mmmnnn786 发表于 2018-9-13 13:54:33 | 显示全部楼层
11111111111111111111

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你已经在论坛发帖求助,并且从坛友或者管理的回复中解决了问题,请编辑帖子并把分类改成【已解决】

如何回报帮助你解决问题的坛友?可以给对方加【热心】【驿站币】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 加入驿站 qq_login

本版积分规则

QQ|小黑屋|手机版|VC驿站 ( 辽ICP备09019393号tongdun|网站地图wx_jqr

GMT+8, 2018-12-13 08:42

Powered by Discuz! X3.4

© 2009-2018 cctry.com

快速回复 返回顶部 返回列表