条款13:以对象管理资源

Use objects to manage resources

假设我们使用一个将用来塑模投资行为的程序库,其中各式各样的透支类型继承自一个root class Investment,进一步假设,这个程序库通过一个工程函数供应我们某特定的Investment对象:

Investment * createInvestment(); //返回指针,指向Inves继承体系内的动态分配对象。调用者有责任删除它。

一如以上注释所言,createInvestment的调用端使用了函数返回后的对象后,有责任删除之。现在考虑有个f函数履行了这个责任:

void f()
{
    Investment *pInv = createInvestment();
    ...
    delete pInv;
}

这看起来妥当,但若干情况下f可能无法删除它-----或许是因为“...”区域内的一个过早的return语句。如果这样一个return被执行,控制流就绝不会触及delete语句。类似情况发生在对createInvestment的使用及delete动作位于某循环内,而该循环由于某个continue或者goto的语句过早退出。最后一种可能是“...”区域内的语句抛出异常,果真如此控制流将再次不会幸临delete。无论delete如何被忽略过去,我们泄露的不只是内含投资对象的那块内存,还包括那些投资对象所保存的任何资源。

当然,谨慎的编写程序可以防止这一类错误,但你必须想想,代码可能会在时间渐渐过去后被修改。一旦软件开始接受维护,可能会有某些人添加return语句或continue语句而未能全然领悟它对函数的资源管理策略造成的后果。更糟的是f的“...”区域有可能调用一个“过去从未抛出异常,却在被“改善”后开始那么做”的函数。因此单纯的依赖“f总是会执行其delete语句”是行不通的。

为确保createInvestment返回的资源总是被释放,我们需要将资源放进对象内,当控制流离开f,该对象的析构函数会自动释放那些资源。实际上这正是隐身与本条款背后的半边想法:把资源放进对象内,我们便可依赖C++的“析构函数自动调用机制”确保资源被释放。

许多资源被动态分配与heap内而后被用于单一区块或函数内。它们应该在控制流离开那个区块或者函数时被释放。标准程序库提供的auto_ptr正是针对这种形势而设计的特制产品。auto_ptr是个“类指针对象”,也就是所谓“智能指针”,其析构函数自动对其所指对象调用delete。下面示范如何使用auto_ptr以避免f函数潜在的资源泄露的可能性:

void f()
{
    std::auto_ptr<Investment> *pInv(createInvestment());
    ...
}

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

获得资源后立刻放进管理对象内。以上代码中createInvestment返回的资源被当作其管理者auto_ptr的初值。实际上“以对象管理资源”的观念被称为“资源取得时机便是初始化时机”(Resource Acquisition Is Initialization;RAII),因为我们几乎总是在获得一笔资源后与同一语句内以它初始化某个管理对象。有时候获得的资源被拿来赋值某个管理对象,但不论哪一种做法,每一笔资源都在获得的同时立刻被放进管理对象中。

管理对象运用析构函数确保资源被释放。不论控制流如何离开区块,一旦对象被销毁,其析构函数自然会被自动调用,于是资源呗释放。如果资源释放动作可能导致抛出异常,事情变得有点棘手。

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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值