对象管理资源

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. SpringMVC结合ajaxfileupload.js实现文件无刷新上传

    直接看代码吧,注释都在里面 首先是web.xml <?xml version="1.0" encoding="UTF-8"?> <web-ap ...

  2. [HIHO1041]国庆出游(DFS, bitset)

    题目链接:http://hihocoder.com/problemset/problem/1041 学会了用C++的bitset哈,可喜可贺.以后遇到超过64位想用位来表示状态就不愁了哈. 这题用bi ...

  3. Mybatis传递多个参数

    方法一: //DAO层的函数方法Public User selectUser(String name,String area); 对应的Mapper.xml <select id="s ...

  4. SQL group by分组查询(转)

    本文导读:在实际SQL应用中,经常需要进行分组聚合,即将查询对象按一定条件分组,然后对每一个组进行聚合分析.创建分组是通过GROUP BY子句实现的.与WHERE子句不同,GROUP BY子句用于归纳 ...

  5. Linux Autotools

    /********************************************************************** * Linux Autotools * 说明: * 我们 ...

  6. LeetCode Binary Tree Maximum Path Sum 二叉树最大路径和(DFS)

    题意:给一棵二叉树,要求找出任意两个节点(也可以只是一个点)的最大路径和,至少1个节点,返回路径和.(点权有负的.) 思路:DFS解决,返回值是,经过从某后代节点上来到当前节点且路径和最大的值.要注意 ...

  7. acdream 1683 村民的怪癖(KMP,经典变形)

    Problem Description 娜娜费劲九牛二虎之力终于把糖果吃完了(说好的吃不完呢?骗人,口亨~),于是,缘溪行,忘路之远近.忽逢桃花林,夹岸数百步,中无杂树,芳草鲜美,落英缤纷,娜娜甚异之 ...

  8. 浅析extendedLayout, automaticallyAdjustsScrollViewInsets, extendedLayoutIncludesOpaqueBars

    参考文章: http://stackoverflow.com/questions/18798792/explaining-difference-between-automaticallyadjusts ...

  9. HDU 2026 首字母变大写

    #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int ma ...

  10. UVa 11520 Fill the Square 填充正方形

    在一个 n * n 网格中填了一些大写字母,你的任务是把剩下的格子中也填满大写字母,使得任意两个相邻格子(即有公共边的格子)中的字母不同.如果有多重填法,则要求按照从上到下,从左到右的顺序把所有格子连 ...