STL容器常用的有顺序存储容器有vector,链式存储容器有list和map。
之前公司项目里有遇到关于容器使用的问题中印象最深的有两点。
1,STL容器不是线程安全的,如果存在并发读写,一定要加锁;
2,使用erase对容器中的元素做删除操作时删除异常或coredump;
根据之前的经验和在网上查询其他相关博客,这里汇总总结下使用erase出问题的情况和正常使用方法。加深一下印象。为了更加赤裸裸的展现问题,这里以通过erase清空容器的代码分析。
顺序存储容器以vector为例,测试vector中元素为{1,2,3,4,5}:
错误使用1:
-
for(vector<int>::iterator it = int_vec.begin(); it != int_vec.end(); it++)
-
{
-
cout<<"Erase item: "<<*it<<endl;
-
int_vec.erase(it);
-
}
错误使用2:
-
for(vector<int>::iterator it = int_vec.begin(); it != int_vec.end();)
-
{
-
cout<<"Erase item: "<<*it<<endl;
-
int_vec.erase(it++);
-
}
上诉两种情况,当当前迭代子被erase掉后,后面的数据会往前移动。再做it++时指向的内存地址对应的数据已经不再是删除之前的数据了。
上述代码执行打印信息如下:
Erase item: 1
Erase item: 3
Erase item: 5
Erase item: 5
Segmentation fault
由于erase后数据的移动导致删除时也没有按照预期的那样从1到5逐个删除元素。
正确使用:
-
for(vector<int>::iterator it = int_vec.begin(); it != int_vec.end();)
-
{
-
cout<<"Erase item: "<<*it<<endl;
-
it = int_vec.erase(it);
-
}
这里不对it做+1操作,而是直接取erase的返回值。按照关于std::vector::erase的说明(Return value Iterator following the last removed element.),erase方法的返回值是当前删除元素的下一个元素。我们直接将返回值赋值给it就可以了。
链式存储容器以map为例
,测试vector中元素为{1,2,3,4,5}:
错误用法:
-
for(map<int, int>::iterator it = int_map.begin(); it != int_map.end();it++)
-
{
-
cout<<"Erase item: "<<it->second<<endl;
-
int_map.erase(it);
-
}
由于for循环第三个表达式“it++”会在for循环逻辑处理完后执行,而此时迭代子it所指向的元素已经被删除掉了,这时候it++是错误的,可能发生无法预期的错误。(不过测试过程中没有遇到错误,保险起见,最好不要这么用)
正确用法1:
-
for(map<int, int>::iterator it = int_map.begin(); it != int_map.end();it)
-
{
-
cout<<"Erase item: "<<it->second<<endl;
-
int_map.erase(it++);
-
}
在将it作为实参拷贝给erase方法的形参后,删除it指向元素前完成it++,是没有问题的。
正确用法2:
-
for(map<int, int>::iterator it = int_map.begin(); it != int_map.end();)
-
{
-
cout<<"Erase item: "<<it->second<<endl;
-
it = int_map.erase(it);
-
}
注:用法2这种用法可能不被支持。参考,erase在C++11和之后版本才支持返回值为itertor类型。
阅读(321) | 评论(0) | 转发(0) |