对象管理资源

createInvestment 函数作用时创建一个invest对象:

void f()
{
  Investment *pInv = createInvestment(); // call factory function
  ... // use pInv
  delete pInv; // release object
}

既然f函数中创建对象,销毁对象的责任也应该由它来承担,但是如果“……”区域出现异常或return提前执行,delete将被跳过,从而造成严重的内存泄露,为了确保无论发生什么情况createInvestment返回的对象始终能记得被销毁,我们就需要将他放入一个对象内,析构函数会自动的释放资源,c++标准库提供auto_ptr,即智能指针,他是个类指针对象,析构函数自动对他调用delete:

void f()
{
  std::auto_ptr<Investment> pInv(createInvestment()); // call factory
  // function
  ... // use pInv as
  // before
} // automatically
  // delete pInv via
  // auto_ptr’s dtor

在使用auto_ptr时要注意,一旦让多个auto_ptr指向同一个对象,资源只存放在最后指向的指针中,其他指针均为null,所以auto_ptr在实际使用时局限性很大,c++11已经舍弃了这一智能指针,他的替代方案时shared_ptr,它能够持续的跟踪共有多少个对象指向资源,在无人指向资源时才删除该资源,但是由于shared_ptr在析构函数中使用的是delete而不是delete[],对于动态分配的数组显然不可取,针对动态数组的智能指针在c++11中并没有提供,但在幸运的事boost中有我们想要的boost::scoped_array和boost::shared_array,google c++ sytle中建议需要使用智能指针的话尽量使用scoped_ptr,只在非常特定的情况下使用 std::tr1::shared_ptr, 例如 STL 容器中的对象。“智能” 指针看上去是指针, 其实是附加了语义的对象. 以 scoped_ptr 为例, scoped_ptr 被销毁时, 它会删除所指向的对象. shared_ptr 也是如此, 并且 shared_ptr 实现了引用计数, 所以最后一个 shared_ptr 对象析构时, 如果检测到引用次数为 0,就会销毁所指向的对象。一般来说,我们倾向于设计对象隶属明确的代码, 最明确的对象隶属是根本不使用指针, 直接将对象作为一个作用域或局部变量使用. 另一种极端做法是, 引用计数指针不属于任何对象. 这种方法的问题是容易导致循环引用, 或者导致某个对象无法删除的诡异状态, 而且在每一次拷贝或赋值时连原子操作都会很慢。

假如将shared_ptr用在互斥器中(mutex objects)

class Lock {
public:
explicit Lock(Mutex *pm)
  : mutexPtr(pm)
  { lock(mutexPtr); } // acquire resource
  ~Lock() { unlock(mutexPtr); } // release resource
private:
  Mutex *mutexPtr;
};

shared_ptr缺省时将引用次数为0时删除所指物,然而在Mutex中,我们要做的释放动作时解锁而不是删除,这就要用到shared_ptr中的删除器来指定代替默认状态下的删除操作,本例中引用计数为0时则自动调用unlock函数

class Lock {
public:
  explicit Lock(Mutex *pm) // init shared_ptr with the Mutex
  : mutexPtr(pm, unlock) // to point to and the unlock func
  { // as the deleter†
    lock(mutexPtr.get()); // see Item15 for info on “get”
  }
private:
  std::tr1::shared_ptr<Mutex> mutexPtr; // use shared_ptr
};

new与智能指针

假设我们有一个函数来解释处理程序的优先权,另一个函数用来动态分配Widge上进行某些优先权处理:

int priority();
void processWidget(std::tr1::shared_ptr<Widget> pw, int priority);

processWidge决定动态分配得来的Widge运用智能指针

processWidget(std::tr1::shared_ptr<Widget>(new Widget), priority());

虽然这里使用了智能指针,但还是会有泄露的发生。

实际参数("std::tr1::shared_ptr<Widget>(new Widget)"),由两部分组成:new Widge表达式和shared_ptr构造函数,但是c++编译器的运行次序可不是按照参数次序来执行,对于priority的调用可能会在new Widge表达式和shared_ptr构造函数两个操作的之前,中间,最后执行,问题在于如果非常不巧的priority在第一个实参的两个操作之间执行,又非常不幸priority调用时抛出异常:

. Execute “new Widget”.
. Call priority.
. Call the tr1::shared_ptr constructor.

第一个new操作的建立 的资源将没有办法回收。

避免这一问题的办法是分离语句,明确调用顺序

std::tr1::shared_ptr<Widget> pw(new Widget); // store newed object
// in a smart pointer in a
// standalone statement
processWidget(pw, priority()); // this call won’t leak

effective c++:资源管理的更多相关文章

  1. Effective C++ ——资源管理

    条款13:以对象来管理资源 在C++中我们经常会涉及到资源的申请与申请,一般都是由关键字new 和 delete来操作的,两者都是成对存在的,缺一不可,否则会出现意想不到的问题,例如: class I ...

  2. Effective C++ —— 资源管理(三)

    条款13 : 以对象管理资源 假设有如下代码: Investment* createInvestment(); //返回指针,指向Investment继承体系内的动态分配对象,调用者有责任删除它 vo ...

  3. C++笔记--thread pool【转】

    版权声明:转载著名出处 https://blog.csdn.net/gcola007/article/details/78750220 背景 刚粗略看完一遍c++ primer第五版,一直在找一些c+ ...

  4. c++内存管理学习纲要

    本系列文章,主要是学习c++内存管理这一块的学习笔记. 时间:6.7-21 之下以技术内幕的开头语,带入到学习C++内存管理的技术中吧: 内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题 ...

  5. Effective C++(15) 在资源管理类中提供对原始资源的访问

      问题聚焦:     资源管理类是为了对抗资源泄露.     如果一些函数需要访问原始资源,资源管理类应该怎么做呢?        关于资源管理的概念总是显得那么的高大上,其实只是抽象一点. 下面用 ...

  6. Effective C++(14) 在资源管理类中小心copying行为

    问题聚焦:     上一条款所告诉我们的智能指针,只适合与在堆中的资源,而并非所有资源都是在堆中的.     这时候,我们可能需要建立自己的资源管理类,那么建立自己的资源管理类时,需要注意什么呢?. ...

  7. 《Effective C++》第3章 资源管理(2)-读书笔记

    章节回顾: <Effective C++>第1章 让自己习惯C++-读书笔记 <Effective C++>第2章 构造/析构/赋值运算(1)-读书笔记 <Effecti ...

  8. 《Effective C++》第3章 资源管理(1)-读书笔记

    章节回顾: <Effective C++>第1章 让自己习惯C++-读书笔记 <Effective C++>第2章 构造/析构/赋值运算(1)-读书笔记 <Effecti ...

  9. Effective C++笔记:资源管理

    资源:动态分配的内存.文件描述器.互斥锁.图形界面中的字型与笔刷.数据库连接以及网络sockets等,无论哪一种资源,重要的是,当你不再使用它时,必须将它还给系统. 条款13:以对象管理资源 当我们向 ...

  10. [Effective C++ --015]在资源管理类中提供对原始资源的访问

    引言 资源管理类是防止资源泄漏的有力武器,但是许多APIs直接指涉资源,除非你发誓永不使用这样的APIs,否则只得绕过资源管理对象(resource-managing objects)直接访问原始资源 ...

随机推荐

  1. Nand flash uboot 命令详解【转】

    转自:http://blog.chinaunix.net/uid-14833587-id-76513.html nand info & nand device 显示flash的信息: DM36 ...

  2. eclipse中启动tomcat报错 java.lang.ClassNotFoundException

    之前启动还好好的,某次启动tomcat就莫名其妙的报了这个java.lang.ClassNotFoundException的错.   检查maven依赖包,发现这个类是存在的. 然后一通clean操作 ...

  3. Android内存管理(2)HUNTING YOUR LEAKS: MEMORY MANAGEMENT IN ANDROID PART 2

    from: http://www.raizlabs.com/dev/2014/04/hunting-your-leaks-memory-management-in-android-part-2-of- ...

  4. 阿里云yum源

    wget -O /etc/yum.repos.d/CentOS-Base-aliyun.repo http://mirrors.aliyun.com/repo/Centos-6.repo 参考:htt ...

  5. hibernate工具类HibernateUtil详解

    1.为什么要用hibernateUtil这个类,先看这段代码:     //加载配置文件信息默认为hiberna.cfg.xml,如果不是的话那么就在config()方法里面去解析他      Con ...

  6. 警惕rapidxml的陷阱:添加节点时,请保证变量的生命周期

    http://www.cnblogs.com/chutianyao/p/3246592.html 项目中要使用xml打包.解析协议,HQ指定了使用rapidxml--号称是最快的xml解析器. 功能很 ...

  7. Javascript学习-闭包

    看的这篇 http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html 各种专业文献上的"闭包" ...

  8. android 开发如何做内存优化

    不少人认为JAVA程序,因为有垃圾回收机制,应该没有内存泄露.其实如果我 们一个程序中,已经不再使用某个对象,但是因为仍然有引用指向它,垃圾回收器就无法回收它,当然该对象占用的内存就无法被使用,这就造 ...

  9. hdu 1044(bfs+状压)

    非常经典的一类题型 没有多个出口.这里题目没有说清楚 Collect More Jewels Time Limit: 2000/1000 MS (Java/Others)    Memory Limi ...

  10. POJ 2528 (线段树 离散化) Mayor's posters

    离散化其实就是把所有端点放在一起,然后排序去个重就好了. 比如说去重以后的端点个数为m,那这m个点就构成m-1个小区间.然后给这m-1个小区间编号1~m-1,再用线段树来做就行了. 具体思路是,从最后 ...