第三章资源管理
条款13:以对象管理资源
RAAI(Resource Acquisition IsInitialization: RAII) 资源取得时机便是初始化时机
n 为防止资源泄漏,请使用RAII对象,它们在构造函数中获得资源并在析构函数中释放资源
n 两个常被使用的RAIIclasses分别是tr1::shared_ptr和auto_ptr。前者通常是较佳选择,因为其copy行为比较直观。若选择auto_ptr,复制动作会使它(被复制物)指向null。
auto_ptr:
auto_ptr在构造时获取对某个对象的所有权,在析构时释放该对象。其析构函数自动对其所指对象调用delete
int*p = new int(0);
auto_ptr<int>ap(p);
auto_ptr<nt> ap(new int(0)); //获得资源后立刻放进管理对象RAAI
从此我们不必关心何时释放p,也不用担心发生异常会有内存泄漏。
要记住几点:
1. auto_ptr析构的时候肯定会删除他所拥有的那个对象,所以两个auto_ptr不能同时拥有同一个对象。为了预防这个问题,auto_ptr有个性质:若通过copy构造函数或copy assignment操作符复制它们,它们会变成null,而复制所得的指针将取得资源的唯一拥有权。
2. auto_ptr的析构函数中删除指针用的是delete,而不是delete[],所以我们不该用auto_ptr来管理一个数组指针。
shared_ptr: 一种“已用计数型智慧指针(RCSP Reference-counting smart pointer)”
RCSP持续追踪共有多少对象指向某笔资源,并在无人指向它时自动删除该资源。但它无法打破环状引用,例如两个其实已经没被使用的对象彼此互指,因而好像还处在“被使用”状态。
条款14:在资源管理类中小心copying行为
n 复制RAII对象必须一并复制它所管理的资源,所以资源的copying行为决定RAII对象的copying行为
n 普通而常见的RAII classcopying行为是:抑制copying 、施行引用计数法。
tr1::shared_ptr允许指定所谓的“删除器”
条款15:在资源管理类中提供对原始资源的访问
n APIs往往要求访问原始资源,所以每一个RAII class应该提供一个“取得其所管理之资源”的办法
n 对原始资源的访问可能经由显示转换或隐式转换。一般而言显式转换比较安全,但隐式转换对客户比较方便。
条款16:成对使用new和delete时要采取相同形式
n 如果你在new表达式中使用[],必须在相应的delete表达式中也使用[]。如果你在new表达式中不使用[],一定不要在相应的delete表达式中使用[]
条款17:以独立语句将newed对象置入智能指针
n 以独立语句将newed对象置入智能指针内。如果不这样做,一旦异常被抛出,有可能导致难以察觉的资源泄漏。
例如
int priority();
voidprocessWidged(std::tr1::shared_ptr<Widget> pw, int priority);
考虑调用
processWidged(std::tr1::shared_ptr<Widget>(newWidget), priority())
可能会产生这样的执行顺序:
1. 执行new Widget
2. 调用priority
3. 调用tr1::shared_ptr构造函数
如果priority的调用导致异常,new Widget返回的指针将会遗失,所以应该采用以下的调用方法:
std::tr1::shared_ptr<Widget> pw(newWidget);
processWidget(pw, priority());