Effective C++ 详解条款13:以对象管理资源(不是只会用delete就够了!)

本条款建议,如果你打算手工释放资源(例如使用delete而非使用一个资源管理类; resource-managing class),容易发生某些错误。罐装式的资源管理类如auto_ptrtr1 : :shared_ptr往往比较能够轻松遵循本条款忠告。

void f( )
{
    Investment* pInv = createInvestment ( );  //调用factory函数
	...
	delete pInv;                             //释放pInv所指对象
}

这看起来妥当,但若干情况下f可能无法删除它得自createInvestment的投资对象-—或许因为"…”区域内的一个过早的return语句。如果这样一个return被执行起来,控制流就绝不会触及 delete语句。类似情况发生在对createInvestment的使用及 delete 动作位于某循环内,而该循环由于某个continuegoto语句过早退出。最后一种可能是…”区域内的语句抛出异常,果真如此控制流将再次不会幸临delete

无论delete 如何被略过去,泄漏的不只是内含投资对象的那块内存,还包括那些投资对象所保存的任何资源。可能会造成添加return语句或continue语句而未能全然领悟它对函数的资源管理策略造成的后果,或者在"…”区域有可能调用一个“过去从未抛出异常,却在被“改善”之后开始那么做”的函数。

因此单纯依赖“f总是会执行其delete语句”是行不通的。

做法:

为确保createInvestment返回的资源总是被释放,需要将资源放进对象内,当控制流离开f,该对象的析构函数会自动释放那些资源。便可倚赖C++的“析构函数自动调用机制”确保资源被释放。

许多资源被动态分配于heap内,而后被用于单一区块或函数内。他们应该在控制流离开那个区块或函数时被释放。auto_ptr正是针对这种形式而设计的。

auto_ptr是个“类指针对象”,也即是智能指针,其析构函数自动对其所指对象调用delete,一定要注意别让多个auto_ptr同时指向同一对象。
下面示范auto_ptr如何使用以避免f函数潜在的资源泄漏可能性:

void f( )
{
    std::auto_ptr<Investment> pInv = (createInvestment() );  //调用factory函数
	...                         //一如既往地使用pInv,经由auto_ptr的析构函数自动删除pInv
}

这个例子示范“以对象管理资源”的两个关键想法:

1、获得资源后立刻放进管理对象内,“以对象管理资源”也被称为“资源取得时机就是初始化时机”(RAII);

2、管理对象运用析构函数确保资源被释放。

auto_ptr性质:若通过copy构造函数或copy assignment操作符复制它们,它们会变成null,而复制所得的指针将取得资源的唯一拥有权!

必须指出,createInvestment返回的“未加工指针”,简直是对资源泄漏的一个死亡邀约,因为调用者极易在这个指针身上忘记调用delete。(即使他们使用auto_ptrtr1::shared ptr来执行delete,他们首先必须记得将createInvestment的返回值存储于智能指针对象内。)为与此问题搏斗,首先需要对createInvestment进行接口修改,条款18将分析。

总结:

为防止资源泄露,请使用RAII对象,他们在构造函数中获得资源并在析构函数中释放资源。

两个常使用的RAII classes分别是tr1::shared_ptrauto_ptr。前者通常是较好选择,因为其copy行为比较直观。若选择auto_ptr,复制动作会使它指向null

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值