快速业务通道

More Effective C++:防止资源泄漏

作者 佚名技术 来源 程序设计 浏览 发布时间 2012-06-30

{
 BookEntry b("Addison-Wesley Publishing Company","One Jacob Way, Reading, MA 01867");
 ...
}

并且在构造b的过程中,一个异常被抛出,b的析构函数不会被调用。而且如果你试图采取主动手段处理异常情况,即当异常发生时调用delete,如下所示:

void testBookEntryClass()
{
 BookEntry *pb = 0;
 try {
  pb = new BookEntry("Addison-Wesley Publishing Company","One Jacob Way, Reading, MA 01867");
  ...
 }
 catch (...) { // 捕获所有异常
  delete pb; // 删除pb,当抛出异常时
 throw; // 传递异常给调用者
}
delete pb; // 正常删除pb
}

你会发现在BookEntry构造函数里为Image分配的内存仍旧被丢失了,这是因为如果new操作没有成功完成,程序不会对pb进行赋值操作。如果BookEntry的构造函数抛出一个异常,pb将是一个空值,所以在catch块中删除它除了让你自己感觉良好以外没有任何作用。用灵巧指针(smart pointer)类auto_ptr(参见条款9)代替raw BookEntry*也不会也什么作用,因为new操作成功完成前,也没有对pb进行赋值操作。

C++拒绝为没有完成构造操作的对象调用析构函数是有一些原因的,而不是故意为你制造困难。原因是:在很多情况下这么做是没有意义的,甚至是有害的。如果为没有完成构造操作的对象调用析构函数,析构函数如何去做呢?仅有的办法是在每个对象里加入一些字节来指示构造函数执行了多少步?然后让析构函数检测这些字节并判断该执行哪些操作。这样的记录会减慢析构函数的运行速度,并使得对象的尺寸变大。C++避免了这种开销,但是代价是不能自动地删除被部分构造的对象。(类似这种在程序行为与效率这间进行折衷处理的例子还可以参见Effective C++条款13)

因为当对象在构造中抛出异常后C++不负责清除对象,所以你必须重新设计你的构造函数以让它们自己清除。经常用的方法是捕获所有的异常,然后执行一些清除代码,最后再重新抛出异常让它继续转递。如下所示,在BookEntry构造函数中使用这个方法:

BookEntry::BookEntry(const string& name,
 const string& address,
 const string& imageFileName,
 const string& audioClipFileName)
 : theName(name), theAddress(address),
 theImage(0), theAudioClip(0)
{
 try { // 这try block是新加入的
  if (imageFileName != "") {
   theImage = new Image(imageFileName);
  }
 if (audioClipFileName != "") {
  theAudioClip = new AudioClip(audioClipFileName);
 }
}
catch (...) { // 捕获所有异常
 delete theImage; // 完成必要的清除代码
 delete theAudioClip;
 throw; // 继续传递异常
}
}

不用为BookEntry中的非指针数据成员操心,在类的构造函数被调用之前数据成员就被自动地初始化。所以如果BookEntry构造函数体开始执行,对象的theName, theAddress 和 thePhones数据成员已经被完全构造好了。这些数据可以被看做是完全构造的对象,所以它们将被自动释放,不用你介入操作。当然如果这些对象的构造函数调用可能会抛出异常的函数,那么哪些构造函数必须去考虑捕获异常,在允许它们继续传递之前完成必需的清除操作。

你可能已经注意到BookEntry构造函数的catch块中的语句与在BookEntry的析构函数的语句几乎一样。这里的代码重复是绝对不可容忍的,所以最好的方法是把通用代码移入一个私有helper function中,让构造函数与析构函数都调用它。

class BookEntry {
 public:
  ... // 同上
 private:
  ...
  void cleanup(); // 通用清除代码
};
void BookEntry::cleanup()
{
 delete theImage;
 delete theAudioClip;
}
BookEntry::BookEntry(const string& nam

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号