构造函数中的异常处理
来源:互联网 发布:用php做99乘法表 编辑:程序博客网 时间:2024/05/16 12:35
构造函数中的异常处理
异常处理,在C++里是一种很细致的工作,必须认真的考虑到每一种出错的可能,并针对之做出合适的处理。这对于构造函数中的异常处理更是如此!构造函数用于对象的初始创建,如果抛出异常,那么它的行为可能不太好预测~特别是资源泄漏问题!
假定我们要建个人信息类,包含一个人的姓名,地址,照片和电话号码,这个类看起来应该是这样的:
class Info
{
private:
string Name;
string Address;
Image* P_Image;
Phone* P_Phone;
public:
Info(const string& name,const string& addr,const string& image,\
const string& phone):Name(name),Address(addr),P_Image(0)\
P_Phone(0)
{
if(image!=" ")
P_Image=new Image(image);
if(phone!=" ")
P_Phone=new Phone(phone);
}
~Info()
{
delete P_Image;
delete P_Phone;
}
};
这里假定Image类和Phone类都有一个以字符串为参数的构造函数,如果Info的构造函数中P_Image的new语句由于出现内存不足而导致的异常时,那么可能事情并没有那么糟,无非就是Info对象无法构造完成,不能生成一个对象而已。但如果是P_Phone的那句new语句出现异常时,由于P_Image已经初始化完成,此时必然会产生内存泄漏。因为无法释放P_Image的内存部分,这里绝对不要妄想会调用析构函数,对于一个尚未初始化完成的对象,那么析构函数又如何能被调用呢~
所以,异常处理就发挥了作用,一个很合适的try-catch子块可以很好的解决这个问题,无非是多加入几行代码而已:
//构造函数,成员初始化列表不变
{
try
{
if(image!=" ")
P_Image=new Image(image);
if(phone!=" ")
P_Phone=new Phone(phone);
}catch(...)
{
delete P_Image;
delete P_Phone;
throw; //传播异常,如果没有,则是吞掉异常
}
这样,无论是谁抛出了异常,都不会导致资源泄漏问题。这里catch子块的部分与构造函数几乎一样,为了避免代码的重复,通常做法是将两个delete子句写入一个函数,并放入到类中的私有部分。啊?你问为什么Name,Address不需要我们手动释放?好吧,它们会在类的构造函数调用之前就构造好,一旦出现异常,它们会像已经构造好的对象一样得到释放,而并不要你插手。这也部分归功于初始化成员列表。
幸福不会来的那么容易的~如果你的Image和Phone是个const指针又如何呢?对于const成员变量,必须在成员初始化类表中给予初始化,那么这个构造函数看起来应该是这样的:
Info(const string& name,const string& addr,const string& image,const string&\
phone):Name(name),Address(addr),P_Image(image==" "?0:new Image(image)\
P_Phone(phone==" "?0:new Phone(phone)){}
由于成员初始化列表中只能出现表达式而不能出现语句,上述的try-catch子块就没有办法用来避免异常的出现啦~这里如果new部分出现异常,那么资源泄漏就没有办法避免了~
C++里有个规则:任何问题都可以通过间接层来得到解决。实现到这个问题就是:我们可以引出两个私有函数,用于产生Image指针和Phone指针,并用来初始化const变量,而在这两个函数中调用try-catch子块进行异常处理:
//位于private部分
Image* CreatImage(const string& image)
{
if(image!=" ")
return new Image(image);
else
return 0;
}
//注意差别
Phone* CreatPhone(const string& phone)
{
try
{
if(phone!=" ")
return new Phone(phone);
else
return 0;
}catch(...)
{
delete P_Image;
throw;
}
}
而相应的构造函数则变为对函数的调用:
Info(const string& name,const string& addr,const string& image,\
const string& phone):Name(name),Address(addr),\
P_Image(CreatImage(image)),P_Phone(CreatPhone(phone)){}
是不是感觉很奇特呢~不过最简单的方法还是以对象来管理资源,利用标准库里的auto_ptr可以更好的解决这个问题,其实现不过是将P_Image和P_Phone生成为atuo_ptr对象而已。如果出现异常,则对象就可以得到析构,从而有效的避免了资源泄漏的问题。
- 构造函数中的异常处理
- 构造函数/析构函数中的异常处理
- C++ 构造/析构函数中的异常处理
- C++学习之构造函数中的异常处理
- C++ 构造/析构函数中的异常处理
- 构造函数的异常处理
- 如何处理C++构造函数中的错误
- C++中构造函数和析构函数中的异常
- C++构造函数、析构函数中的异常
- c++构造函数和析构函数中的异常
- C++构造函数与析构函数中的“异常”
- C++中的构造函数与拷贝构造的优化处理
- 构造,析构,异常处理
- Java的构造函数抛出异常如何处理?
- C++中异常处理中的构造和析构
- [C++]异常处理中的拷贝构造操作(copy constructor)
- C++-面试题:深度拷贝与构造函数中的异常
- 异常和构造函数
- 单链表
- 基于Cactus的接口自动化
- Shell编程
- Google SVN
- 设计模式之命令模式
- 构造函数中的异常处理
- Hibernate+Oracle使用序列
- Lucene 实战:快速开始 创建索引
- Hibernate中实体的三种状态
- Hibernate获取序列
- Linux和Oracle常用工具
- 归并排序和插入排序
- java面试资料大全
- MongoDB系列之一:windows安装