c++构造函数和析构函数中的异常

本文探讨了C++中构造函数和析构函数抛出异常的情况。当构造函数抛出异常时,若已分配堆内存,需确保释放以防止内存泄漏。而析构函数中抛出异常可能导致栈回退时的错误,一般应避免析构函数抛出异常,尤其是在不是最后一个析构函数执行时。堆上生成的对象在析构函数抛出异常时可能导致内存溢出。建议尽量避免析构函数中抛出异常,以维护程序的稳定性和内存管理的正确性。

情况一:构造函数中有异常抛出

构造函数中有异常抛出,需要注意如果该构造函数中已在堆中生成了对象,要在构造函数中进行异常处理去释放堆中资源或者使用智能指针,因为这时构造函数未执行成功,对象还未创建成功,在栈回退时不会调用析构函数,进而造成内存泄漏;若在堆中生成的对象则无需担心,因为在栈回退时会释放。

测试代码如下:

#include <iostream>

using namespace std;

class A
{
      public:
      A()
      {
            cout<<"create A"<<endl;
      }
      ~A()
      {
            cout<<"delete A"<<endl;
      }
};

class Base
{
      A * a;
public:
    Base()
    {
          a=new A();
          try
          {
                cout<<"create exception"<<endl;
                throw 1;
          }
          catch(...)
          {
                delete a;
                throw 1;
          }
    }
    void fun()     {   throw 1;    }
    ~Base()        {  delete a;    }
};

int main()
{
   try
   {
       Base base;
       //base.fun();
   }
   catch (...)
   {
        cout <<"get the catch"<<endl;
   }
}


如上所示的处理方式就避免了内存泄漏

情况二:析构函数中有异常抛出

析构函数中尽量避免有异常抛出(如果有抛出,尽量在析构函数中catch到并处理),因为很容易导致在栈回退时会出现异常处理中出现了异常(除非是在退出所属作用域时调用的最后一个析构函数,这时有异常抛出不会出现问题,因为栈回退时不会出现异常处理中出现异常),这是很明显到语义错误,这就会构成逻辑上到无限循环,这种情况下是会报错的,因此需要注意。另外一种情况就是所有到对象均在堆上生成,这时可以在析构函数中抛出异常,因为是显式的调用析构函数,异常处理中在栈回退时不会调用析构函数,但是这种情况很容易造成内存溢出。

a.栈回退时有异常抛出,出现错误:

#include <iostream>

using namespace std;

class Base
{
public:
    void fun()     {   throw 1;    }
    ~Base()        {   throw 2;    }
};

int main()
{
   try
   {
      Base base;
       base.fun();
   }
   catch (int e)
   {
        cout <<"get the catch:"<<e<<endl;
   }
}

如上所示,当将base.fun()注释时,程序正常运行,当没注释时,就出现了异常处理中出现了异常到错误。

b.在堆上生成对象,但是造成了内存泄漏:

#include <iostream>

using namespace std;

class Base
{
public:
    void fun()     {   throw 1;    }
    ~Base()        {   throw 2;    }
};

int main()
{
      Base* base=new Base();
      Base* base1=new Base();
   try
   {
       base->fun();
       delete base;
       delete base1;
   }
   catch (int e)
   {
        cout <<"get the catch:"<<e<<endl;
        try
        {
               delete base;
        }catch(int e1)
        {
              cout <<"get the catch:"<<e1<<endl;
        }

   }
}

如上所示,导致了base1没有销毁,

综合上面两个例子,我们应该尽量避免在析构函数抛出异常,因为这会导致很多错误的产生。

注:以上为个人的一些浅显的理解,如有错误之处,还望批评指正。


参考:

http://blog.csdn.net/sysylh20080531/article/details/39035915


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值