条款13:以对象管理资源
获得资源后立刻放进管理对象内,这个管理类通常被称为RAII classes。
管理对象运用析构函数确保资源被释放。
通常可以使用tr1::shared_ptr和auto_ptr来完成对资源指针的封装,但是请记住tr1::shared_ptr和auto_ptr内做delete而不是delete[]动作,因此请不要在动态分配的数组身上使用tr1::shared_ptr和auto_ptr。
要点:
-
为防止资源泄漏,请使用RAII对象,它们在构造函数中获得资源并在析构函数中释放资源
-
两个常被使用的RAII classes分别是tr1::shared_ptr和auto_ptr。前者通常是较佳选择,因为其copy行为比较直观。若选择auto_ptr,复制动作会使它(被复制物)指向null。
条款14:在资源管理类中小心copying行为
一般情况,每一位RAII class作者一定需要面对的一问题是“当一个RAII对象被复制,会发生什么事?”,大多时候你会选择以下几种可能:
禁止复制。许多时候允许RAII对象被复制并不合理,但是有时候倒是有这个需求,如果复制动作对RAII class并不合理,你可以通过将copying操作声明为private来禁止它。
对底层资源使用“引用计数法”。有时候我们希望保有资源,直到它的最后一个使用者被销毁。这种情况下复制RAII对象时,应该将资源的“被引用数递增”。tr1::shared_ptr便是如此。因此也可以将RAII类内使用tr1::shared_ptr便可以实现引用计数拷贝行为。
复制底部资源。在此情况下复制资源管理对象,应该同时也复制其所包覆的资源,即“深度拷贝”。
转移底部资源的拥有权。某些场合下你可能希望确保永远只有一个RAII对象指向一个未加工资源,即使RAII对象被复制依然如此,此时资源会从被复制物转移到目标物,auto_ptr便是如此。
要点:
-
复制RAII对象必须一并复制它所管理的资源,所以资源copying行为决定RAII对象的copying行为。
-
普遍而觉的RAII class copying行为是:抑制copying、施行引用计数法。不过其它行为也都可能被实现。
条款15:在资源管理类中提供对原始资源的访问
虽然资源管理类非常有用,但是你并不能保证所有的API都是访问的你的资源管理类,也有可能有的API会访问原始资源,因此通常需要提供一个访问原始资源的办法。
要点:
-
APIs往往要求访问原始资源,所以每一个RAII class应该提供一个“取得其所管理之资源”的办法。
-
对原始资源的访问可能经由显式转换或隐匿转换。一般而言显式转换比较安全,但隐式转换对客户比较方便。
条款16:成对使用new和delete时要采取相同形式
要点:
-
如果你在new表达式中使用[],必须在相应的delete表达式中也使用[]。如果你在new表达式中不使用[],一定不要在相应的delete表达式中使用[]。
条款17:以独立语句将newed对象置入智能指针
如下写法可能会出现资源泄漏:
processWidget(std::tr1::shared_ptr(new Widget),priority());
因为在调用processWidget之前,编译器必须创建代码做以下三件事:调用priority;执行new Widget;调用tr1::shared_ptr构造函数。但是为了生成更高效的代码,C++编译可能会重新排序这段代码,那么priority的调用则可能排在第一或第二或第三执行。如果编译器选择以第二位执行它,如果它抛出异常那便可能出现内存泄漏。因此可以这样解决:
std::tr1::shared_ptr pw(new Widget);
processWidget(pw,priority());
要点:
-
以独立语句将newed对象存储于智能指针内。如果不这样做,一旦异常被抛出,有可能导致难以察觉的资源泄漏。
阅读(1319) | 评论(0) | 转发(0) |