Effective STL 条款33

原创 2004年01月21日 13:27:00

条款33:提防在指针的容器上使用类似remove的算法

你在管理一堆动态分配的Widgets,每一个都可能通过检验,你把结果指针保存在一个vector中:

class Widget{
public:
 ...
 bool isCertified() const; // 这个Widget是否通过检验
 ...
};
vector<Widget*> v;   // 建立一个vector然后用
...    // 动态分配的Widget
v.push_back(new Widget);  // 的指针填充

当和v工作一段时间后,你决定除去未通过检验的Widget,因为你不再需要它们了。记住条款43的警告尽量用算法调用代替显式循环和读过的条款32关于remove和erase之间关系的描述,你自然会想到转向erase-remove惯用法,虽然这次你使用了remove_if:

v.erase(remove_if(v.begin(), v.end(),    // 删除未通过检验的
   not1(mem_fun(&Widget::isCertified))), // Widget指针
    v.end());    // 关于mem_fun的信息
        // 参见条款41

突然你开始担心erase的调用,因为你朦胧的记起条款7关于摧毁容器中的一个指针也不会删除指针指向的东西的讨论。这是个合理的担心,但在这里,太晚了。当调用erase时,极可能你已经泄漏了资源。担心erase,是的,但首先,担心一下remove_if。

我们假设在调用remove_if前,v看起来像这样,我已经指出了未通过检验的Widget:

在调用remove_if后,一般来说v看起来像这样(包含从remove_if返回的迭代器):

如果你看不懂这个转换,请转向条款32,因为它准确地解释了调用remove——或者,在这个例子里,remove_if——做了什么。

资源泄漏的理由现在很明朗了。指向Widget B和C的“删除的”指针被vector中后面的“不删除的”指针覆盖。没有什么指向两个未通过检验的Widget,它们也没有被删除,它们的内存和其他资源泄漏了。

一旦remove_if和erase返回后,情况看起来像这样:

这造成资源泄漏尤其明显了,现在你也很清楚为什么应该努力避免在动态分配的指针的容器上使用remove和类似算法(也就是,remove_if和unique)。在很多情况下,你会发现partition算法(参见条款31)是合理的替代品。

如果你无法避免在那样的容器上使用remove,排除这个问题一种方法是在应用erase-remove惯用法之前先删除指针并设置它们为空,然后除去容器中的所有空指针:

void delAndNullifyUncertified(Widget*& pWidget)  // 如果*pWidget是一个
{       // 未通过检验Widget,
 if (!pWidget->isCertified()) {   // 删除指针
  delete pWidget;    // 并且设置它为空
  pWidget = 0;
 }
}
for_each(v.begin(), v.end(),   // 把所有指向未通过检验Widget的
   delAndNullifyUncertified); // 指针删除并且设置为空
v.erase(remove(v.begin(), v.end(),   // 从v中除去空指针
   static_cast<Widget*>(0)), // 0必须映射到一个指针,
   v.end());   // 让C++可以
      // 正确地推出remove的
      // 第三个参数的类型

当然,这假设vector并不容纳任何你想保留的空指针。如果有的话,你可能必须自己写循环来按你的方式删除指针。在你遍历容器时从容器中删除元素有一些细微的要注意的地方,在考虑那种方法之前确定已经读过条款9

如果你把指针的容器替换成执行引用计数的智能指针的容器,删除相关的困难就不存在了,你可以直接使用erase-remove惯用法:

template<typename T>     // RCSP = “引用计数
class RCSP { ...};      // 智能指针”
typedef RCSP< Widget> RCSPW;    // RCSPW = “RCSP to Widget”
vector<RCSPW > v;      // 建立一个vector,用动态
...       // 分配Widget的
v.push_back(RCSPW(new Widget));    // 智能指针填充它
...
v.erase(remove_if(v.begin(), v.end(),   // erase未通过检验的
  not1 (mem_fun(&Widget::isCertified))), // Widget的指针
   v.end());    // 没有资源泄漏

要让这些工作,你的智能指针类型就必须可以(比如RCSP<Widget>)隐式转换为相应的内建指针类型(比如Widget*)。那是因为容器持有智能指针,但被调用的成员函数(比如Widget::isCertified)要的是内建指针。如果不存在隐式转换,你的编译器会抗议的。

如果在你的程序工具箱中碰巧没有一个引用计数智能指针模板,你应该从Boost库中得到shared_ptr模板。关于Boost的介绍,请看条款50

不管你怎么选择处理动态分配指针的容器,通过引用计数智能指针、在调用类似remove的算法前手动删除和废弃指针或者一些你自己发明的技术,本条款的指导意义依然一样:提防在指针的容器上使用类似remove的算法。没有注意这个建议的人只能造成资源泄漏。

effective stl 第19条:理解相等(equality)和等价(equivalence)的区别

#include #include #includeusing namespace std;bool ciStringCompare(const string l, const string r) {...
  • u014110320
  • u014110320
  • 2016年09月20日 23:36
  • 251

Effective STL学习笔记-条款19

条款19 了解相等和等价的区别了解相等和等价的区别例如find函数,或者一个set容器插入一个值得时候都会进行比较。但是它们的行为是不同的,find是通过 operator==,而set::inser...
  • gx864102252
  • gx864102252
  • 2017年08月27日 21:01
  • 105

Effective STL条款17-条款18

条款17:使用交换技巧来修正过剩容量本节条款告诉我们,如果你有一个vector的容器,容器的容量是10000,但是,现在只用了1,那么为了节省内存,我们应该只保留使用的vector容量,多余的容量应该...
  • u011058765
  • u011058765
  • 2016年04月21日 09:10
  • 291

Effective STL 中文版(完整版)

 Winter总算找到《Effective STL》的完整中文版了,奉献给大家。书中作者解释了怎样结合STL组件来在库的设计得到最大的好处。这样的信息允许你对简单、直接的问题开发简单、直接的解决方案,...
  • WinterTree
  • WinterTree
  • 2005年01月16日 01:23
  • 16319

《Effective C++》:条款28-条款29

条款28避免返回handles指向对象内部成分:指的是不能返回对象内部数据/函数的引用、指针等。 条款29为异常安全而努力是值得的:指的是要有异常处理机制,避免发生异常时造成资源泄露等问题。...
  • KangRoger
  • KangRoger
  • 2015年02月19日 19:47
  • 1401

Effective C++ 条款2

尽量以const、enum、inline替换#define首先,大家要明白一个道理。#define是什么,有什么作用。很简单,大家都知道#define实现宏定义,如下代码:#define Flag 1...
  • u011058765
  • u011058765
  • 2015年06月19日 12:06
  • 502

《Effective C++》:条款41-条款42

条款41了解隐式接口和编译期多态 条款42了解typename的双重意义条款
  • KangRoger
  • KangRoger
  • 2015年03月10日 22:13
  • 1250

Effective STL- 熟悉非标准的散列容器(hash 容器)

 条款25:熟悉非标准散列容器STL程序员一般用不了多久就开始惊讶,“vector、list、map,很好,但是散列(hash)表在哪里"?唉,在标准C++库里没有任何散列表。 每个人都同意这是个不幸...
  • bichenggui
  • bichenggui
  • 2009年10月21日 22:21
  • 1915

《Effective C++》:条款44-条款45

条款44将与参数无关的代码抽离templates 条款45运用成员函数模板接受所有兼容类型...
  • KangRoger
  • KangRoger
  • 2015年03月12日 22:01
  • 1513

Effective STL学习笔记-条款33

提防在指针容器上使用类似remove的算法假如有一个Widget类型,当它符合某一标准之后(处理完毕之后)我们准备从容器中删除,并且会每隔一段时间进行一次,类如下:class Widget { pub...
  • gx864102252
  • gx864102252
  • 2017年11月12日 22:23
  • 55
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Effective STL 条款33
举报原因:
原因补充:

(最多只允许输入30个字)