快速业务通道

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

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

如果你正在开发一个具有多媒体功能的通讯录程序。这个通讯录除了能存储通常的文字信息如姓名、地址、电话号码外,还能存储照片和声音(可以给出他们名字的正确发音)。

为了实现这个通信录,你可以这样设计:

class Image { // 用于图像数据
 public:
  Image(const string& imageDataFileName);
  ...
};
class AudioClip { // 用于声音数据
 public:
  AudioClip(const string& audioDataFileName);
  ...
};
class PhoneNumber { ... }; // 用于存储电话号码
class BookEntry { // 通讯录中的条目
 public:
  BookEntry(const string& name,
  const string& address = "",
  const string& imageFileName = "",
  const string& audioClipFileName = "");
  ~BookEntry();
  // 通过这个函数加入电话号码
  void addPhoneNumber(const PhoneNumber& number);
  ...
 private:
  string theName; // 人的姓名
  string theAddress; // 他们的地址
  list thePhones; // 他的电话号码
  Image *theImage; // 他们的图像
  AudioClip *theAudioClip; // 他们的一段声音片段
};

通讯录的每个条目都有姓名数据,所以你需要带有参数的构造函数(参见条款3),不过其它内容(地址、图像和声音的文件名)都是可选的。注意应该使用链表类(list)存储电话号码,这个类是标准C++类库(STL)中的一个容器类(container classes)。(参见Effective C++条款49 和本书条款35)

编写BookEntry 构造函数和析构函数,有一个简单的方法是:

BookEntry::BookEntry(const string& name,const string& address,
 const string& imageFileName,
 Const string& audioClipFileName)
 : theName(name), theAddress(address),
 theImage(0), theAudioClip(0)
 {
  if (imageFileName != "") {
   theImage = new Image(imageFileName);
  }
  if (audioClipFileName != "") {
   theAudioClip = new AudioClip(audioClipFileName);
  }
 }
 BookEntry::~BookEntry()
 {
  delete theImage;
  delete theAudioClip;
 }

构造函数把指针theImage和theAudioClip初始化为空,然后如果其对应的构造函数参数不是空,就让这些指针指向真实的对象。析构函数负责删除这些指针,确保BookEntry对象不会发生资源泄漏。因为C++确保删除空指针是安全的,所以BookEntry的析构函数在删除指针前不需要检测这些指针是否指向了某些对象。

看上去好像一切良好,在正常情况下确实不错,但是在非正常情况下(例如在有异常发生的情况下)它们恐怕就不会良好了。

请想一下如果BookEntry的构造函数正在执行中,一个异常被抛出,会发生什么情况呢?:

if (audioClipFileName != "") {
 theAudioClip = new AudioClip(audioClipFileName);
}

一个异常被抛出,可以是因为operator new(参见条款8)不能给AudioClip分配足够的内存,也可以因为AudioClip的构造函数自己抛出一个异常。不论什么原因,如果在BookEntry构造函数内抛出异常,这个异常将传递到建立BookEntry对象的地方(在构造函数体的外面。 译者注)。

现在假设建立theAudioClip对象建立时,一个异常被抛出(而且传递程序控制权到BookEntry构造函数的外面),那么谁来负责删除theImage已经指向的对象呢?答案显然应该是由BookEntry来做,但是这个想当然的答案是错的。BookEntry根本不会被调用,永远不会。

C++仅仅能删除被完全构造的对象(fully contructed objects), 只有一个对象的构造函数完全运行完毕,这个对象才能被完全地构造。所以如果一个BookEntry对象b做为局部对象建立,如下:

void testBookEntryClass()

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站: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号