C++构造函数、析构函数与抛出异常

【本文链接】

http://www.cnblogs.com/hellogiser/p/constructor-destructor-exceptions.html

【问题】

构造函数可以抛出异常么?析构函数可以吗?

【分析】

从语法上来说,构造函数和析构函数都可以抛出异常。但从逻辑上和风险控制上,构造函数可以,析构函数不推荐抛出异常。

(1)构造函数可以抛出异常

无论何时,从构造函数中抛出异常都是可以的。动态创建对象要进行两个操作:分配内存和调用构造函数。若在分配内存时出错,会抛出bad_alloc异常;若在调用构造函数初始化时出错,会不会存在内存泄漏呢?答案是不会。

new运算符保证不会出现内存泄漏:

 C++ Code 
1
 
T *p = new T;

将被编译器转换给类似下面的样子:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
void allocate_and_construct()
{
    
// 第一步,分配原始内存,若失败则抛出bad_alloc异常
    try
    {
        
// 第二步,调用构造函数构造对象
        new (p)T;       // placement new: 只调用T的构造函数
    }
    
catch(...)
    {
        
delete p;     // 释放第一步分配的内存
        throw;          // 重抛异常,通知应用程序
    }
}

(2)析构函数不推荐抛出异常,如果析构函数可能抛出异常,那么必须要求在析构函数内消化所有异常或者结束程序。

more effective c++提出两点理由(析构函数不能抛出异常的理由)

1)如果析构函数抛出异常,则异常点之后的程序不会执行,如果析构函数在异常点之后执行了某些必要的动作比如释放某些资源,则这些动作不会执行,会造成诸如资源泄漏的问题。 [正常情况下调用析构函数抛出异常导致资源泄露]

2)通常异常发生时,c++的机制会调用已经构造对象的析构函数来释放资源,此时若析构函数本身也抛出异常,则前一个异常尚未处理,又有新的异常,会造成程序崩溃的问题。 [在发生异常的情况下调用析构函数抛出异常,会导致程序崩溃]

 解决方案:

1) 如果某个操作可能会抛出异常,class应提供一个普通函数(而非析构函数),来执行该操作。目的是给客户一个处理错误的机会。

2) 如果析构函数中异常非抛不可,那就用try catch来将异常吞下,必须要把这种可能发生的异常完全封装在析构函数内部,决不能让它抛出函数之外。

【参考】

http://blog.csdn.net/liuxialong/article/details/6586083

http://www.cnblogs.com/fly1988happy/archive/2012/04/11/2442765.html

http://www.cnblogs.com/KevinSong/p/3323372.html