情况一:构造函数中有异常抛出
构造函数中有异常抛出,需要注意如果该构造函数中已在堆中生成了对象,要在构造函数中进行异常处理去释放堆中资源或者使用智能指针,因为这时构造函数未执行成功,对象还未创建成功,在栈回退时不会调用析构函数,进而造成内存泄漏;若在堆中生成的对象则无需担心,因为在栈回退时会释放。
测试代码如下:
#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
本文探讨了C++中构造函数和析构函数抛出异常的情况。当构造函数抛出异常时,若已分配堆内存,需确保释放以防止内存泄漏。而析构函数中抛出异常可能导致栈回退时的错误,一般应避免析构函数抛出异常,尤其是在不是最后一个析构函数执行时。堆上生成的对象在析构函数抛出异常时可能导致内存溢出。建议尽量避免析构函数中抛出异常,以维护程序的稳定性和内存管理的正确性。

1358

被折叠的 条评论
为什么被折叠?



