文章目录
1.构造函数抛出异常导致内存泄漏
2.使用智能指针管理内存资源
参考文献
从语法上来说,构造函数可以抛出异常。但从逻辑上和风险控制上,构造函数中尽量不要抛出异常。万不得已,一定要注意防止内存泄露。
1.构造函数抛出异常导致内存泄漏
在 C++ 构造函数中,既需要分配内存,又需要抛出异常时要特别注意防止内存泄露的情况发生。因为在构造函数中抛出异常,在概念上将被视为该对象没有被成功构造,因此当前对象的析构函数就不会被调用。同时,由于构造函数本身也是一个函数,在函数体内抛出异常将导致当前函数运行结束,并释放已经构造的成员对象,包括其基类的成员,即执行直接基类和成员对象的析构函数。考察如下程序。
#include
using namespace std;
class C {
int m;
public:
C(){
cout<<"in C constructor"<~C(){
cout<<"in C destructor"<
};
class A {
public:
A(){
cout<<"in A constructor"<~A(){
cout<<"in A destructor"<
};
class B:public A {
public:
C c;
char* resource;
B() {
resource=new char[100];
cout<<"in B constructor"< throw -1;
}
~B() {
cout<<"in B destructor"< delete[] resource;
}
};
int main() {
try {
B b;
}
catch(int) {
cout<<"catched"<}
}
程序输出结果:
in A constructor
in C constructor
in B constructor
in C destructor
in A destructor
catched
从输出结果可以看出,在构造函数中抛出异常,当前对象的析构函数不会被调用,如果在构造函数中分配了内存,那么会造成内存泄露,所以要格外注意。
此外,在构造对象b的时候,先要执行其直接基类A的构造函数,再执行其成员对象c的构造函数,然后再进入类B的构造函数。由于在类B的构造函数中抛出了异常,而此异常并未在构造函数中被捕捉,所以导致类B的构造函数执行中断,对象b并未构造完成。在类B的构造函数“回滚”的过程中,c的析构函数和类A的析构函数相继被调用。最后,由于b并没有被成功构造,所以main()函数结束时,并不会调用b的析构函数,也就很容易造成内存泄露。
2.使用智能指针管理内存资源
使用 RAII(Resource Acquisition is Initialization)技术可以避免内存泄漏。RAII 即资源获取即初始化,也就是说在构造函数中申请分配资源,在析构函数中释放资源。因为 C++ 的语言机制保证了,当一个对象创建的时候,自动调用构造函数,当对象超出作用域的时候会自动调用析构函数。所以,在 RAII 的指导下,我们应该使用类来管理资源,将资源和对象的生命周期绑定。智能指针是 RAII 最具代表的实现,使用智能指针,可以实现自动的内存管理,再也不需要担心忘记 delete 造成的内存泄漏。
因此,当构造函数不得已抛出异常时,可以利用智能指针 unique_ptr 来防止内存泄露。参考如下程序:
#include
using namespace std;
class A {
public:
A() {
cout << "in A constructor" << endl; }
~A() {
cout << "in A destructor" << endl; }
};
class B {
public:
unique_ptr pA;
B():pA(new A) {
cout << "in B constructor" << endl;
throw - 1;
}
~B() {
cout << "in B destructor" << endl;
}
};
int main() {
try {
B b;
}
catch (int) {
cout << "catched" << endl;
}
}
程序运行结果:
in A constructor
in B constructor
in A destructor
catched
从程序的运行结果来看,通过智能指针对内存资源的管理,尽管在类B构造函数抛出异常导致类B析构函数未被执行,但类 A 的析构函数仍然在对象 pA 生命周期结束时被调用,避免了资源泄漏。
----
参考文献
[1] Scott Meyers.More Effective C++[M].北京:电子工业出版社,2013:58-61
[2] 构造函数、析构函数抛出异常的问题
[3] C++中的RAII介绍
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/hz/135638.html