C++ Container 以及 STL 相关的常用操作 和 注意事项
2011-11-20 22:08
489 查看
1. 对于list和各种associative containers(set, map, sultiset, multimap),erase()操作不会使指向被删元素以外的元素的iterator或reference失效,所以可以用下面的方法来删:
如果ShouldErase(...)函数比较复杂,可能还要借助boost::bind()来构造unary function。如果情况再复杂一些的话(比如要把删掉的元素输出),那这个方法可能就不好使了。另外,使用remove_if(...)时ShouldErase肯定不能内联展开了,所以如果效率敏感的话,也要注意。一种基于的方法是:
这个方法的一个严重问题在于:当seq_container是vector,deque等连续存储容器时,seq_container.erase(itr)的复杂度可能是线性的!
所以我认为当效率敏感时,应该自己用for来模仿remove_if,可以在尽量不损失效率的情况下获得足够的灵活性。
补充:对于list,上面两种for循环的删法都是可以使用的,但一般会用第二个(seq_container)那种,因为毕竟list是sequential container。另外list有自己的remove和remove_if成员函数,不使用std::remove或std::remove_if.
2. std::vector a; 我们知道a.size()和a.capacity()不一定相等,也就是a可能有一定的预留空间。如果想释放这些预留空间怎么办呢?C++03里是用“swap大法” ,vector<int>(a).swap(a);;但到了C++11有了shrink_to_fit了就直接a.shrink_to_fit();就行了。注意:swap大法和shrink_to_fit()都可能会导致reallocation——执行前后a[0]的地址可能已经变化了(g++4.5.2上的实验结果)。另外,这里有很重要的一点需要说明:C++标准保证调用vector的clear()操作是不会更改capacity的(不知道新的标准有没有进一步保证不会发生reallocation,不过就算没保证,难道真的会有编译器在不改变capacity的情况下去reallocation?),这是很有用的一个保证——实际中经常希望一次reserve()到容量需求上界以后,反复增删元素和清空不会触发reallocation。
Update: 在《Effective STL》第15条发现了一段话:可以通过判断if (v.size() < v.capacity())来确定下次push_back或者single element insertion会不会触发reallocation。但是注意在非末尾进行insertion的话,即使没有触发reallocation,也会使从插入位置直到末尾的所有元素的iterators/pointers/references失效。
for (itr = asso_container.begin(); itr != asso_container .end(); ) { if (ShouldErase(*itr)) { asso_container.erase(itr++); } else { ++itr; } }对于vector或者deque,erase()操作还会影响指向其他元素的iterator和reference,所以不能这么删。比较有文化的方法是用STL的remove_if()和对区间的erase()操作配合来做这个事:
container.erase(remove_if(container.begin(), container.end(), ShouldErase), container.end());
如果ShouldErase(...)函数比较复杂,可能还要借助boost::bind()来构造unary function。如果情况再复杂一些的话(比如要把删掉的元素输出),那这个方法可能就不好使了。另外,使用remove_if(...)时ShouldErase肯定不能内联展开了,所以如果效率敏感的话,也要注意。一种基于的方法是:
for (itr = seq_container.begin(); itr != seq_container.end(); ) { if (ShouldErase(*itr)) { DoOtherThings(*itr); itr = seq_container.erase(itr); } else { ++itr; } }
这个方法的一个严重问题在于:当seq_container是vector,deque等连续存储容器时,seq_container.erase(itr)的复杂度可能是线性的!
所以我认为当效率敏感时,应该自己用for来模仿remove_if,可以在尽量不损失效率的情况下获得足够的灵活性。
补充:对于list,上面两种for循环的删法都是可以使用的,但一般会用第二个(seq_container)那种,因为毕竟list是sequential container。另外list有自己的remove和remove_if成员函数,不使用std::remove或std::remove_if.
2. std::vector a; 我们知道a.size()和a.capacity()不一定相等,也就是a可能有一定的预留空间。如果想释放这些预留空间怎么办呢?C++03里是用“swap大法” ,vector<int>(a).swap(a);;但到了C++11有了shrink_to_fit了就直接a.shrink_to_fit();就行了。注意:swap大法和shrink_to_fit()都可能会导致reallocation——执行前后a[0]的地址可能已经变化了(g++4.5.2上的实验结果)。另外,这里有很重要的一点需要说明:C++标准保证调用vector的clear()操作是不会更改capacity的(不知道新的标准有没有进一步保证不会发生reallocation,不过就算没保证,难道真的会有编译器在不改变capacity的情况下去reallocation?),这是很有用的一个保证——实际中经常希望一次reserve()到容量需求上界以后,反复增删元素和清空不会触发reallocation。
Update: 在《Effective STL》第15条发现了一段话:可以通过判断if (v.size() < v.capacity())来确定下次push_back或者single element insertion会不会触发reallocation。但是注意在非末尾进行insertion的话,即使没有触发reallocation,也会使从插入位置直到末尾的所有元素的iterators/pointers/references失效。
相关文章推荐
- Qt中如何使用样式表QPalette以及相关注意事项(转)
- CreateProcess重定向输出与错误以及相关注意事项
- 【转】二叉树的实现及操作以及指针使用和删除注意事项
- maven nexus deploy方式以及相关注意事项(增加eclipse执行maven deploy)
- dojo mobile笔记1--moveTo与url的区别与共性以及相关注意事项
- 顺序链表的常用操作实现及注意事项
- hive 创建、删除、截断表基本操作及相关注意事项
- Hadoop HDFS文件常用操作及注意事项(更新)
- LDAP相关操作注意事项
- lucene4.3注意事项以及相关代码
- Qt中如何禁掉所有UI操作以及注意事项(转)
- 二叉树常用操作算法集、解释及注意事项
- 和内存操作相关的注意事项
- iOS巅峰之iPhone适配的相关内容以及机型适配时的注意事项
- Linux上安装Apache,oralce,cognos服务器操作步骤以及注意事项
- HDFS常用文件操作命令及注意事项
- 关于mybatis批量更新操作的相关注意事项
- Scrapy抓取网页相关问题解决以及注意事项总结
- 字符串操作练习以及scanf()的注意事项