构造函数与析构函数中抛出异常

1.在构造函数中抛出异常,由于对象没有完全构造,所以不会调用析构函数,
如果在构造函数中动态分配内存,就会产生内存泄露,通常,我们在构造
函数中只做基本的初始化,如果需要复杂的初始化,我们一般会编写Init(),
在构造函数中调用Init(),并通过UnInit()处理异常,这时候,往往会在
UnInit()和析构函数发生代码重复,为了使代码结构更优美,最好采用
智能指针。

exception.cpp

#include <iostream>
using std::cout;
using std::endl;


class Base
{
public:
        Base() { cout << "construct in base construct" << endl; }
        ~Base() { cout << "destruct in base" << endl; }
};

class Derive : public Base
{
public:
        Derive()
        {
                pszArr = new char[10];
                throw "exception in derive construct";
        }

        ~Derive()
        {
                cout << "destruct in derive" << endl;
                if (NULL != pszArr)
                {
                        delete []pszArr;
                        pszArr = NULL;
                }
        }

private:
        char *pszArr;

};

int main()
{
        try
        {
                Derive derive;
        }
        catch(const char *e)
        {
                cout << e << endl;
        }

        return 0;
}

root@sym:/test/exception# g++ -g exception.cpp -o main
root@sym:/test/exception# ./main
construct in base construct
destruct in base
exception in derive construct

root@sym:/test/exception# valgrind -v --leak-check=full ./main

 


推荐写法:

#include <iostream>
using std::cout;
using std::endl;


class Base
{
public:
        Base() { cout << "construct in base construct" << endl; }
        ~Base() { cout << "destruct in base" << endl; }
};

class Derive : public Base
{
public:
        Derive() : num(10)
        {
                try
                {
                        Init();
                }
                catch (...)
                {
                        UnInit();
                }
        }

        ~Derive()
        {
                cout << "destruct in derive" << endl;
                if (NULL != pszArr)
                {
                        delete []pszArr;
                        pszArr = NULL;
                }
        }

        void Init()
        {
                pszArr = new char[num];
                throw "exception in Init function";
        }

        void UnInit()
        {
                if (NULL != pszArr)
                {
                        delete []pszArr;
                        pszArr = NULL;
                }
        }

private:
        char *pszArr;
        int  num;
};

int main()
{
        try
        {
                Derive derive;
        }
        catch(const char *e)
        {
                cout << e << endl;
        }

        return 0;
}


2.c++不推荐从析构函数中抛出异常,因为析构函数可能在对象正常结束生命周期时调用,
也可能在有异常发生时从函数堆栈清理时调用。前一种情况抛出异常不会有无法预料的结果,可以正常捕获;
但后一种情况下,因为已经发生了异常而导致函数的局部变量的析构函数被调用,此时析构函数又抛出异常。
在两个异常同时存在的情况下,异常处理机制只能调用terminate()。

当某段代码抛出一个异常时,会在堆栈中寻找catch处理程序。Catch处理程序可以是在堆栈执行的0个或者多个函数调用。
当发现一个catch时,堆栈会释放所有中间堆栈帧,直接跳到定义catch处理程序的堆栈层。
堆栈释放(stack unwinding)意味着调用所有具有局部作用域的名称的析构函数,并忽略在当前执行点之前的每个函数中所有的代码。

When an exception is thrown in a program, the stack begins to unroll, and objects get destroyed by
calling their destructors. If the destructor of an object being destroyed during stack unrolling throws
another exception which leaves the destructor, the C++ library will immediately terminate the program by
calling the terminate() function. What follows from this is the rule that destructors should never let
exceptions out. An exception thrown inside a destructor must be handled inside the same destructor.

http://www.viva64.com/en/b/0391/

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值