zhouqijie

以对象管理资源(RAII)

以对象管理资源的两个关键想法:

“以对象管理资源”的观念常被称为资源获得时机就是初始化时机(RAII),因为我们几乎总是在获得一笔资源后于同一语句以它初始化某个管理对象。

无论控制流如何离开区块,一旦对象被销毁(例如当前对象离开作用域)其析构函数自然会被自动调用,于是资源被释放。

RAII常用的智能指针:

析构函数自动对所指对象调用delete。
(赋值的时候,原指针会变成NULL)
(注意不能让多个auto_ptr指向同一个对象)

引用计数智能指针。
(注意shared_ptr不能打破环状引用)

总结:

为防止资源泄露,请使用RAII对象,他们在构造函数中获得资源并在析构函数中释放资源。
两个常用的RAII类分别是shared_ptrauto_ptr,前者通常是最佳选择。



在资源管理类中小心复制行为

当一个RAII对被复制,你的可能选择:

  1. 禁止复制。(许多时候允许RAII对象被复制并不合理)
  2. 对底层资源祭出“引用计数法”。(使用shared_ptr成员变量)
  3. 深度复制底层资源。(只要你喜欢,可以针对一份资源拥有其任意数量的副本)
  4. 转移所有权。(类似auto_ptr的行为)

总结:

复制RAII对象必须一并复制它所管理的资源,所以资源的复制行为决定RAII对象的复制行为。
普遍而常见的RAII类复制行为是:抑制复制、施行引用计数法。不过其他行为也都可能被实现。



在资源管理类中提供对原始资源的访问

很多API往往要求访问原始资源。除非你发誓永不调用这样的API,你应该让每个RAII类提供一个取得原始资源的办法。
对原始资源的访问可能经由显示转换或者隐式转换。一般而言显示转换比较安全,隐式转换对客户方便。



成对使用newdelete时要采取相同形式

如果你在new表达式中使用[],必须在相应的delete表达式中也使用[]。如果你在new表达式中不使用[],一定不要在相应的delete表达式中使用[]



以独立语句将newed对象置入智能指针

以独立语句将newed对象存储置入只能指针。如果不这样做,抛出异常可能导致难以察觉的资源泄露。

processWidget( shared_ptr<Widget>(new Widget),   priority());
//上述调用可能造成泄露资源。    
//new Widget是最先调用的,但是shared_ptr()和priority()谁先调用对于编译器弹性很大。    
//如果调用priority()时抛出异常,资源指针尚未被置入shared_ptr,就导致了资源泄露。    

(END)