Effective STL 学习笔记 32 ~ 33
Effective STL 学习笔记 32 ~ 33
*/-->
div.org-src-container {
font-size: 85%;
font-family: monospace;
}
pre.src {
background-color:#f8f4d7
}
p {font-size: 15px}
li {font-size: 15px}
Table of Contents
1 记得 Remove 后要 Erase
Item 9 中已经提到过,如果真的想要用 remove 从容器中删除元素,必须要在 remove 之后使用 erase
。其原因在于: remove 接受的参数是通用的迭代器,而不是容器,它不知道容器的任何信息,也就无法从容器中删除元素: remove doesn't really remove anything, because it can't.
remove 只保证在其返回的迭代器之前的元素为有效数据(符合条件的数据),但它既无法删除被 remove
的数据,也不能保证返回的迭代器之后的数据位无效数据(不符合条件的数据)。这一点与某些容器内置的 remove member function 不一样:这些 member function 会真正的把数据删除掉:
// For vector, we have to call erase after remove.
vector<int> v;
// ....
vector<int>::iterator endPos = remove(v.begin(), v.end(), 99); // Remove 99 from vector, returns last valid position.
v.erase(posEnd, v.end()); // Erase all elements after posEnd. // For list, the member function remove is enough:
list<int> l;
//...
l.remove(99); // this will erase all 99 in the list.
2 remove, container, pointer
Item 6 中提到,在容器中放置对象指针容易混乱,这里如果对存放指针的容器调用 remove-erase idom
的话,会发生什么事情?
1: class Widget
2: {
3: public:
4: Widget();
5: virtual ~Widget();
6: bool IsCertified();
7: };
8:
9: vector<Widget*> v;
10:
11: // push lots of widget pointers to v.
12:
13: v.erase(remove(v.begin(), v.end(), not1(mem_fun(&Widget::IsCertified))), v.end());
内存泄露。
那么将第 13 行换成下面的表达式呢?
14: vector<Widget*> endPos = remove(v.begin(), v.end(), not(mem_fun(&Widget::IsCertified)));
15: for_each(endPos, v.end(), [](Widget* pw){if(pw) delete pw;});
16: v.erase(endPos, v.end());
第 14 行将所有的 endPos 之后的指针先释放,然后再去 erase。前面刚刚提过, remove 不会保证返回的迭代器之后的元素都为无效值,第 14 行有可能会将本该保留的对象给释放掉,还有可能会将该释放的不释放。结果可能会 Crash 或者内存泄露。
我们应该保证在 remove 过程中,一旦发现不合要求的数据,马上将其删除,例如下面的例子:
#include <vector>
#include <iterator>
#include <algorithm>
#include <iostream>
#include <stdio.h> using namespace std; class Widget
{
public:
Widget(int i);
virtual ~Widget();
bool IsCertified();
void Show();
private:
int m_i;
}; /* See description in header file. */
Widget::Widget(int i)
: m_i(i)
{
} /* See description in header file. */
Widget::~Widget()
{
printf ("Deleting Obj: %p, value: %d\n", this, m_i);
} /* See description in header file. */
bool Widget::IsCertified()
{
return m_i % 2 == 0;
} /* See description in header file. */
void Widget::Show()
{
printf ("\tObj: %p, value: %d\n", this, m_i);
} bool DeleteIfUncitified(Widget* p)
{
if (p && !p->IsCertified())
{
delete p;
return true;
}
return false;
} int main(int argc, char *argv[])
{
vector<Widget*> v;
for (int i = 0; i < 20; ++i)
{
Widget* p = new Widget(i);
v.push_back(p);
} random_shuffle(v.begin(), v.end()); printf ("Before remove, size: %lu, contents:\n", v.size());
for_each(v.begin(), v.end(),
[](Widget* p){
if (p) p->Show();
else printf("Obj is Null");});
printf ("\nNow removing...\n");
v.erase(remove_if(v.begin(), v.end(), DeleteIfUncitified), v.end());
printf ("\nAfter remove, size: %lu, contents:\n", v.size());
for_each(v.begin(), v.end(),
[](Widget* p){
if (p) p->Show();
else printf("Obj is Null");}); return 0;
}
其输出为:
Welcome to the Emacs shell ~/tmp $ ./test
Before remove, size: 20, contents:
Obj: 0x7f8b31c038d0, value: 19
Obj: 0x7f8b31c03870, value: 3
Obj: 0x7f8b31c039e0, value: 14
Obj: 0x7f8b31c039f0, value: 15
Obj: 0x7f8b31c03890, value: 10
Obj: 0x7f8b31c03850, value: 2
Obj: 0x7f8b31c03900, value: 6
Obj: 0x7f8b31c038b0, value: 17
Obj: 0x7f8b31c03920, value: 8
Obj: 0x7f8b31c038a0, value: 4
Obj: 0x7f8b31c039c0, value: 12
Obj: 0x7f8b31c03910, value: 7
Obj: 0x7f8b31c038f0, value: 5
Obj: 0x7f8b31c039b0, value: 11
Obj: 0x7f8b31c03860, value: 1
Obj: 0x7f8b31c03880, value: 9
Obj: 0x7f8b31c03840, value: 0
Obj: 0x7f8b31c03a00, value: 16
Obj: 0x7f8b31c039d0, value: 13
Obj: 0x7f8b31c038c0, value: 18 Now removing...
Deleting Obj: 0x7f8b31c038d0, value: 19
Deleting Obj: 0x7f8b31c03870, value: 3
Deleting Obj: 0x7f8b31c039f0, value: 15
Deleting Obj: 0x7f8b31c038b0, value: 17
Deleting Obj: 0x7f8b31c03910, value: 7
Deleting Obj: 0x7f8b31c038f0, value: 5
Deleting Obj: 0x7f8b31c039b0, value: 11
Deleting Obj: 0x7f8b31c03860, value: 1
Deleting Obj: 0x7f8b31c03880, value: 9
Deleting Obj: 0x7f8b31c039d0, value: 13 After remove, size: 10, contents:
Obj: 0x7f8b31c039e0, value: 14
Obj: 0x7f8b31c03890, value: 10
Obj: 0x7f8b31c03850, value: 2
Obj: 0x7f8b31c03900, value: 6
Obj: 0x7f8b31c03920, value: 8
Obj: 0x7f8b31c038a0, value: 4
Obj: 0x7f8b31c039c0, value: 12
Obj: 0x7f8b31c03840, value: 0
Obj: 0x7f8b31c03a00, value: 16
Obj: 0x7f8b31c038c0, value: 18
~/tmp $
(转载请注明出处,使用许可:署名-非商业性使用-相同方式共享 3.0 中国大陆许可协议 。)
Effective STL 学习笔记 32 ~ 33的更多相关文章
- Effective STL 学习笔记 39 ~ 41
Effective STL 学习笔记 39 ~ 41 */--> div.org-src-container { font-size: 85%; font-family: monospace; ...
- Effective STL 学习笔记 Item 38 : Design functor classes for pass-by-value
Effective STL 学习笔记 Item 38 : Design functor classes for pass-by-value */--> div.org-src-container ...
- Effective STL 学习笔记 Item 34: 了解哪些算法希望输入有序数据
Effective STL 学习笔记 Item 34: 了解哪些算法希望输入有序数据 */--> div.org-src-container { font-size: 85%; font-fam ...
- Effective STL 学习笔记 31:排序算法
Effective STL 学习笔记 31:排序算法 */--> div.org-src-container { font-size: 85%; font-family: monospace; ...
- Effective STL 学习笔记 Item 30: 保证目标区间足够大
Effective STL 学习笔记 Item 30: 保证目标区间足够大 */--> div.org-src-container { font-size: 85%; font-family: ...
- Effective STL 学习笔记 Item 26: Prefer Iterator to reverse_iterator and const_rever_itertor
Effective STL 学习笔记 Item 26: Prefer Iterator to reverse_iterator and const_rever_itertor */--> div ...
- Effective STL 学习笔记: Item 22 ~ 24
Effective STL 学习笔记: Item 22 ~ 24 */--> div.org-src-container { font-size: 85%; font-family: monos ...
- Effective STL 学习笔记 Item 21:Comparison Function 相关
Effective STL 学习笔记 Item 21:Comparison Function 相关 */--> div.org-src-container { font-size: 85%; f ...
- Effective STL 学习笔记:19 ~ 20
Effective STL 学习笔记:19 ~ 20 */--> div.org-src-container { font-size: 85%; font-family: monospace; ...
随机推荐
- cocoaPods安装、更新第三方库
pod install 换成 pod install --verbose --no-repo-update pod update 换成 pod update --verbose --no-repo-u ...
- laravel 中的 toSql 获取带参数的 sql 语句
默认情况下,toSql 获取到的 sql 里面的参数使用 "?" 代替的,如下: DB::table('user')->where('id', 1)->toSql(); ...
- CF&&CC百套计划2 CodeChef December Challenge 2017 Total Diamonds
https://www.codechef.com/DEC17/problems/VK18 #include<cstdio> #include<iostream> #includ ...
- angularJS DOM element() $compile()
我们可以使用angularJS来动态地添加和删除节点 与jQuery不同的是,html字符串需要经过$compile()方法的编译才能产生html的DOM的node 注意element()方法的使用 ...
- [问题]通过IIS宿主发布WCF服务,客户端添加服务引用出错的解决办法
环境配置:Web服务器:Windows Server 2008,iis7.5,.net4.0客户端:XPsp3 vs2010 sp1 问题描述:1.确定WCF服务访问地址 http://servic ...
- 基本控件文档-UISlider属性
CHENYILONG Blog 基本控件文档-UISlider属性 Fullscreen UISlide属性技术博客http://www.cnblogs.com/ChenYilong/ 新浪微 ...
- html向js传递id
html获取id方法: <div id="thediv1" style="display:block" onclick="ceshi(this. ...
- 2017中国大学生程序设计竞赛 - 网络选拔赛 1005 HDU 6154 CaoHaha's staff (找规律)
题目链接 Problem Description "You shall not pass!" After shouted out that,the Force Staff appe ...
- python模块-logging的智商上限
logging,故名肆意就是正在进行日志,我艹,这个文化底蕴! logging是python内置的日志模块,便于日常程序的日志写入和输出 logging共分为5个日志等级,分别是: debug , i ...
- JavaScript 优雅的实现方式包含你可能不知道的知识点
有些东西很好用,但是你未必知道:有些东西你可能用过,但是你未必知道原理. 实现一个目的有多种途径,俗话说,条条大路通罗马.很多内容来自平时的一些收集以及过往博客文章底下的精彩评论,收集整理拓展一波,发 ...