新技能Get!

问题

对于c++里面的容器, 我们可以使用iterator进行方便的遍历. 但是当我们通过iterator对vector/map等进行修改时, 我们就要小心了, 因为操作往往会导致iterator失效, 之后的行为都变得不可预知. 比如:

  1. #include <iostream>
  2. #include <vector>
  3.  
  4. using namespace std;
  5.  
  6. int main()
  7. {
  8. vector<int> a = {12, 23, 34, 45, 56, 67, 78, 89};
  9.  
  10. for (auto iter = a.begin(); iter != a.end(); ++iter) {
  11. if (*iter > 30) {
  12. a.erase(iter);
  13. }
  14. }
  15.  
  16. for (const auto &element : a) {
  17. cout<<element<<endl;
  18. }
  19.  
  20. return 0;
  21. }
  22.  
  23. 输出:
  24.  
  25. 12
  26. 23
  27. 45
  28. 67
  29. 89

cplusplus的reference里对 std::vector::erase 的描述是:

Iterators, pointers and references pointing to position (or first) and beyond are invalidated, with all iterators, pointers and references to elements before position (or first) are guaranteed to keep referring to the same elements they were referring to before the call.

只有删除元素前面的iterator还保持有效, 之后的遍历行为不可预知.

解决方案

对于vector, erase会返回下一个iterator, 因此我们可以使用如下的方法:

  1. #include <iostream>
  2. #include <vector>
  3.  
  4. using namespace std;
  5.  
  6. int main()
  7. {
  8. vector<int> a = {12, 23, 34, 45, 56, 67, 78, 89};
  9.  
  10. auto iter = a.begin();
  11. while (iter != a.end()) {
  12. if (*iter > 30) {
  13. iter = a.erase(iter);
  14. }
  15. else {
  16. ++iter;
  17. }
  18. }
  19.  
  20. for (const auto &element : a) {
  21. cout<<element<<endl;
  22. }
  23.  
  24. return 0;
  25. }
  26.  
  27. 输出:
  28.  
  29. 12
  30. 23

  

对于map, 删除iterator只会影响当前的iterator, 因此使用for循环就够了, 比如:

  1. #include <iostream>
  2. #include <map>
  3.  
  4. using namespace std;
  5.  
  6. int main()
  7. {
  8. map<int, int> a = {{1, 12}, {2, 23}, {3, 34}, {4, 45}, {5, 56}, {6, 67}};
  9.  
  10. for (auto iter = a.begin(); iter != a.end(); ++iter) {
  11. if (iter->second > 30) {
  12. a.erase(iter);
  13. }
  14. }
  15.  
  16. for (const auto &element : a) {
  17. cout<<element.first<<" : "<<element.second<<endl;
  18. }
  19.  
  20. return 0;
  21. }
  22.  
  23. 输出:
  24.  
  25. 1 : 12
  26. 2 : 23

  但是更推荐的做法是在erase前让iterator指向下一个元素

  1. #include <iostream>
  2. #include <map>
  3.  
  4. using namespace std;
  5.  
  6. int main()
  7. {
  8. map<int, int> a = {{1, 12}, {2, 23}, {3, 34}, {4, 45}, {5, 56}, {6, 67}};
  9.  
  10. auto iter = a.begin();
  11. while (iter != a.end()) {
  12. if (iter->second > 30) {
  13. a.erase(iter++);
  14. }
  15. else {
  16. ++iter;
  17. }
  18. }
  19.  
  20. for (const auto &element : a) {
  21. cout<<element.first<<" : "<<element.second<<endl;
  22. }
  23.  
  24. return 0;
  25. }
  26.  
  27. 输出:
  28.  
  29. 1 : 12
  30. 2 : 23

  

参考资料

http://stackoverflow.com/questions/4645705/vector-erase-iterator

http://stackoverflow.com/questions/4600567/how-can-i-delete-elements-of-a-stdmap-with-an-iterator

c++如何遍历删除map/vector里面的元素的更多相关文章

  1. 【遍历集合】Java遍历List,Map,Vector,Set的几种方法

    关于list,map,set的区别参考http://www.cnblogs.com/qlqwjy/p/7406573.html 1.遍历list @Test public void testList( ...

  2. 删除map、list集合元素总结

    @Testpublic void removeElementFromMap(){Map<Integer, String> test = new HashMap<Integer, St ...

  3. Java 循环遍历删除set list中的元素

    删除List和Set中的某些元素 错误代码的写法: Set<String> set = new HashSet<String>(); set.add("aaaaaa& ...

  4. map/vector遍历删除

    map遍历删除 map<int, vector<int>>::iterator it = g_map.begin(); for (; it != g_map.end(); /* ...

  5. map,vector 等容器内容的循环删除问题(C++)

    map,vector 等容器内容的循环删除问题(C++) map,vector等容器的循环删除不能用普通的方法删除: for(auto p=list.begin();p!=list.end();p++ ...

  6. Set,List,Map,Vector,ArrayList的区别(转)

    JAVA的容器---List,Map,Set Collection ├List │├LinkedList │├ArrayList │└Vector │ └Stack └Set Map ├Hashtab ...

  7. STL容器的遍历删除

    STL容器的遍历删除 今天在对截包程序的HashTable中加入计时机制时,碰到这个问题.对hash_map中的每个项加入时间后,用查询函数遍历hash_map,以删除掉那些在表存留时间比某个阈值长的 ...

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

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

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

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

随机推荐

  1. Spring MVC 文件上传

    1.form的enctype=”multipart/form-data” 这个是上传文件必须的 2.applicationContext.xml中 <bean id=”multipartReso ...

  2. Adapter(适配器)-类对象结构型模式

    1.意图 将一个类接口转换成客户希望的另外一个接口.Adapter模式使那些原本不能一起工作的类,可以一起工作. 2.别名 包装器 Wrapper. 3.动机 一个应用可能会有一些类具有不同的接口,并 ...

  3. 03-JAVA方法

    答:我发现这两个方法的返回类型以及参数类型不一样. package 汉诺塔问题; /**汉诺塔问题*作者:徐浩军 日期:16.10.16 天气:晴*/ public class TowersOfHan ...

  4. python学习笔记-Day7

    class Province: # 静态字段(类变量/属性) country = '中国' def __init__(self, name): # 普通字段(实例变量/属性) self.name = ...

  5. Two Sum & Add Two Numbers

    Two Sum 题目:https://leetcode.com/problems/two-sum/ class Solution(object): def twoSum(self, nums, tar ...

  6. 设置EditText光标位置

    editext.setSelection(int index);

  7. NFS配置

    一,配置nfs服务端 nfs服务端IP:192.168.1.10 1,安装nfs [root@localhost ~]# yum install -y nfs-utils Loaded plugins ...

  8. [Ng]Angular应用点概览

      1. 使用模块化写法. var app = angular.module('myApp', []); app.controller('TextController', function($scop ...

  9. noip2014-day1-t2

    题目描述:无向连通图G 有n 个点,n - 1 条边.点从1 到n 依次编号,编号为 i 的点的权值为W i ,每条边的长度均为1 .图上两点( u , v ) 的距离定义为u 点到v 点的最短距离. ...

  10. Android性能优化方法(五)

    有时候,我们的页面中可能会包含一些布局,这些布局默认是隐藏的,当用户触发了一定的操作之后,隐藏的布局才会显示出来.比如,我们有一个Activity用来显示好友的列表,当用户点击Menu中的“导入”以后 ...