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; ...
随机推荐
- python基础之生成器迭代器
1 生成器: 为什么要有生成器? 就拿列表来说吧,假如我们要创建一个list,这个list要求格式为:[1,4,9,16,25,36……]这么一直持续下去,直到有了一万个元素的时候为止.如果我们要创建 ...
- python 资产扫描01
本地建立的三个文件: Asset1.txt 用来保存扫描到的资产 Asset2.txt 用来导入给定的资产 Repeat.txt 保存重复的资产 程序的功能: 1.资产扫描,以 位置:资产 格式保存到 ...
- Git1:Git简介
目录 什么是版本控制系统 集中式版本控制系统 分布式版本控制系统 Git起源 Git特性 什么是版本控制系统 版本控制系统是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统.版本控制 ...
- JavaScript中的arguments详解
1. arguments arguments不是真正的数组,它是一个实参对象,每个实参对象都包含以数字为索引的一组元素以及length属性. (function () { console.log(ar ...
- Centos7远程桌面 vnc/vnc-server的设置
Centos7与Centos6.x有了很大的不同. 为了给一台服务器装上远程桌面,走了不少弯路.写这篇博文,纯粹为了记录,以后如果遇到相同问题,可以追溯. 1.假定你的系统没有安装vnc的任何软件,那 ...
- servlet程序使用tomcat启动报错
根据书上的需求写了一些简单的servlet代码,启动时报错: 严重: A child container failed during startjava.util.concurrent.Executi ...
- Java并发编程原理与实战二十八:信号量Semaphore
1.Semaphore简介 Semaphore,是JDK1.5的java.util.concurrent并发包中提供的一个并发工具类. 所谓Semaphore即 信号量 的意思. 这个叫法并不能很好地 ...
- 20155331 2016-2017-2 《Java程序设计》第6周学习总结
20155331 2016-2017-2 <Java程序设计>第6周学习总结 教材学习内容总结 输入/输出基础 很多实际的Java应用程序不是基于文本的控制台程序.尽管基于文本的程序作为教 ...
- 2016-2017-2 《Java程序设计》第五周学习总结
20155223 2006-2007-2 <Java程序设计>第五周学习总结 教材学习内容总结 第八章 try.catch语法:若程序发生错误,执行流程就调离错误点,然后比较catch括号 ...
- 2017ACM暑期多校联合训练 - Team 9 1010 HDU 6170 Two strings (dp)
题目链接 Problem Description Giving two strings and you should judge if they are matched. The first stri ...