Chinaunix首页 | 论坛 | 博客

Tea

  • 博客访问: 19547
  • 博文数量: 13
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 130
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-24 10:40
个人简介

骚年

文章分类

全部博文(13)

文章存档

2014年(13)

我的朋友

分类: LINUX

2014-07-03 00:20:19

STL容器常用的有顺序存储容器有vector,链式存储容器有list和map。

之前公司项目里有遇到关于容器使用的问题中印象最深的有两点。
    1,STL容器不是线程安全的,如果存在并发读写,一定要加锁;
    2,使用erase对容器中的元素做删除操作时删除异常或coredump;


    根据之前的经验和在网上查询其他相关博客,这里汇总总结下使用erase出问题的情况和正常使用方法。加深一下印象。为了更加赤裸裸的展现问题,这里以通过erase清空容器的代码分析。

顺序存储容器以vector为例,测试vector中元素为{1,2,3,4,5}:
错误使用1:

点击(此处)折叠或打开

  1. for(vector<int>::iterator it = int_vec.begin(); it != int_vec.end(); it++)
  2.   {
  3.     cout<<"Erase item: "<<*it<<endl;
  4.     int_vec.erase(it);
  5.   }
错误使用2:

点击(此处)折叠或打开

  1. for(vector<int>::iterator it = int_vec.begin(); it != int_vec.end();)
  2.   {
  3.     cout<<"Erase item: "<<*it<<endl;
  4.     int_vec.erase(it++);
  5.   }
    上诉两种情况,当当前迭代子被erase掉后,后面的数据会往前移动。再做it++时指向的内存地址对应的数据已经不再是删除之前的数据了。
    上述代码执行打印信息如下:
Erase item: 1
Erase item: 3
Erase item: 5
Erase item: 5
Segmentation fault
    由于erase后数据的移动导致删除时也没有按照预期的那样从1到5逐个删除元素。

正确使用:

点击(此处)折叠或打开

  1. for(vector<int>::iterator it = int_vec.begin(); it != int_vec.end();)
  2.   {
  3.     cout<<"Erase item: "<<*it<<endl;
  4.     it = int_vec.erase(it);
  5.   }
这里不对it做+1操作,而是直接取erase的返回值。按照关于std::vector::erase的说明Return value     Iterator following the last removed element.),erase方法的返回值是当前删除元素的下一个元素。我们直接将返回值赋值给it就可以了。


链式存储容器以map为例,测试vector中元素为{1,2,3,4,5}:
错误用法:

点击(此处)折叠或打开

  1. for(map<int, int>::iterator it = int_map.begin(); it != int_map.end();it++)
  2.   {
  3.     cout<<"Erase item: "<<it->second<<endl;
  4.     int_map.erase(it);
  5.   }
由于for循环第三个表达式“it++”会在for循环逻辑处理完后执行,而此时迭代子it所指向的元素已经被删除掉了,这时候it++是错误的,可能发生无法预期的错误。(不过测试过程中没有遇到错误,保险起见,最好不要这么用

正确用法1:

点击(此处)折叠或打开

  1. for(map<int, int>::iterator it = int_map.begin(); it != int_map.end();it)
  2.   {
  3.     cout<<"Erase item: "<<it->second<<endl;
  4.     int_map.erase(it++);
  5.   }
在将it作为实参拷贝给erase方法的形参后,删除it指向元素前完成it++,是没有问题的。

正确用法2:

点击(此处)折叠或打开

  1. for(map<int, int>::iterator it = int_map.begin(); it != int_map.end();)
  2.   {
  3.     cout<<"Erase item: "<<it->second<<endl;
  4.     it = int_map.erase(it);
  5.   }
注:用法2这种用法可能不被支持。参考,erase在C++11和之后版本才支持返回值为itertor类型。
阅读(321) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~