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}

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 $

Effective STL 学习笔记 32 ~ 33的更多相关文章

  1. Effective STL 学习笔记 39 ~ 41

    Effective STL 学习笔记 39 ~ 41 */--> div.org-src-container { font-size: 85%; font-family: monospace; ...

  2. 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 ...

  3. Effective STL 学习笔记 Item 34: 了解哪些算法希望输入有序数据

    Effective STL 学习笔记 Item 34: 了解哪些算法希望输入有序数据 */--> div.org-src-container { font-size: 85%; font-fam ...

  4. Effective STL 学习笔记 31:排序算法

    Effective STL 学习笔记 31:排序算法 */--> div.org-src-container { font-size: 85%; font-family: monospace; ...

  5. Effective STL 学习笔记 Item 30: 保证目标区间足够大

    Effective STL 学习笔记 Item 30: 保证目标区间足够大 */--> div.org-src-container { font-size: 85%; font-family: ...

  6. 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 ...

  7. Effective STL 学习笔记: Item 22 ~ 24

    Effective STL 学习笔记: Item 22 ~ 24 */--> div.org-src-container { font-size: 85%; font-family: monos ...

  8. Effective STL 学习笔记 Item 21:Comparison Function 相关

    Effective STL 学习笔记 Item 21:Comparison Function 相关 */--> div.org-src-container { font-size: 85%; f ...

  9. Effective STL 学习笔记:19 ~ 20

    Effective STL 学习笔记:19 ~ 20 */--> div.org-src-container { font-size: 85%; font-family: monospace; ...

随机推荐

  1. python基础之生成器迭代器

    1 生成器: 为什么要有生成器? 就拿列表来说吧,假如我们要创建一个list,这个list要求格式为:[1,4,9,16,25,36……]这么一直持续下去,直到有了一万个元素的时候为止.如果我们要创建 ...

  2. python 资产扫描01

    本地建立的三个文件: Asset1.txt 用来保存扫描到的资产 Asset2.txt 用来导入给定的资产 Repeat.txt 保存重复的资产 程序的功能: 1.资产扫描,以 位置:资产 格式保存到 ...

  3. Git1:Git简介

    目录 什么是版本控制系统 集中式版本控制系统 分布式版本控制系统 Git起源 Git特性 什么是版本控制系统 版本控制系统是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统.版本控制 ...

  4. JavaScript中的arguments详解

    1. arguments arguments不是真正的数组,它是一个实参对象,每个实参对象都包含以数字为索引的一组元素以及length属性. (function () { console.log(ar ...

  5. Centos7远程桌面 vnc/vnc-server的设置

    Centos7与Centos6.x有了很大的不同. 为了给一台服务器装上远程桌面,走了不少弯路.写这篇博文,纯粹为了记录,以后如果遇到相同问题,可以追溯. 1.假定你的系统没有安装vnc的任何软件,那 ...

  6. servlet程序使用tomcat启动报错

    根据书上的需求写了一些简单的servlet代码,启动时报错: 严重: A child container failed during startjava.util.concurrent.Executi ...

  7. Java并发编程原理与实战二十八:信号量Semaphore

    1.Semaphore简介 Semaphore,是JDK1.5的java.util.concurrent并发包中提供的一个并发工具类. 所谓Semaphore即 信号量 的意思. 这个叫法并不能很好地 ...

  8. 20155331 2016-2017-2 《Java程序设计》第6周学习总结

    20155331 2016-2017-2 <Java程序设计>第6周学习总结 教材学习内容总结 输入/输出基础 很多实际的Java应用程序不是基于文本的控制台程序.尽管基于文本的程序作为教 ...

  9. 2016-2017-2 《Java程序设计》第五周学习总结

    20155223 2006-2007-2 <Java程序设计>第五周学习总结 教材学习内容总结 第八章 try.catch语法:若程序发生错误,执行流程就调离错误点,然后比较catch括号 ...

  10. 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 ...