文章目录

  • 1.构造函数抛出异常导致内存泄漏
  • 2.使用智能指针管理内存资源
  • 参考文献

从语法上来说,构造函数可以抛出异常。但从逻辑上和风险控制上,构造函数中尽量不要抛出异常。万不得已,一定要注意防止内存泄露。

1.构造函数抛出异常导致内存泄漏

在 C++ 构造函数中,既需要分配内存,又需要抛出异常时要特别注意防止内存泄露的情况发生。因为在构造函数中抛出异常,在概念上将被视为该对象没有被成功构造,因此当前对象的析构函数就不会被调用。同时,由于构造函数本身也是一个函数,在函数体内抛出异常将导致当前函数运行结束,并释放已经构造的成员对象,包括其基类的成员,即执行直接基类和成员对象的析构函数。考察如下程序。

#include <iostream>
using namespace std;class C {int m;
public:C(){cout<<"in C constructor"<<endl;}~C(){cout<<"in C destructor"<<endl;}
};class A {public:A(){cout<<"in A constructor"<<endl;}~A(){cout<<"in A destructor"<<endl;}
};class B:public A {public:C c;char* resource;B() {resource=new char[100];cout<<"in B constructor"<<endl;throw -1;}~B() {cout<<"in B destructor"<<endl;delete[]  resource;}
};int main() {try {B b;}catch(int) {cout<<"catched"<<endl;}
}

程序输出结果:

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 <iostream>
using namespace std;class A {public:A() { cout << "in A constructor" << endl; }~A() { cout << "in A destructor" << endl; }
};class B {public:unique_ptr<A> 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介绍

C++ 构造函数抛出异常注意事项相关推荐

  1. java构造函数可以抛出异常吗_关于java:使构造函数抛出异常是一种好习惯吗?...

    本问题已经有最佳答案,请猛点这里访问. 让构造函数抛出异常是一个好的实践吗?例如,我有一个类Person,我将age作为它的唯一属性.现在我提供的课程是 class Person{ int age; ...

  2. java 构造函数抛出异常,构造函数抛出异常;嵌套异常是java.lang.NoClassDefFoundError:javax/servlet/ServletContext...

    我正在尝试使用MockMVC设置Junit测试. 从这个link – "要么不能使用Servlet API,要么你需要在类路径上提供它". 我在pom.xml中添加了以下内容但是没 ...

  3. C++中构造函数和析构函数可以抛出异常吗?

    C++中构造函数和析构函数可以抛出异常吗? 一.  析构函数 参照<Effective C++>中条款08:别让异常逃离析构函数.  总结如下: 1. 不要在析构函数中抛出异常!虽然C++ ...

  4. 27.能否在构造函数中抛出异常?析构函数呢?

    首先,我们要明确一点!一个函数执行的过程中,如果抛出异常,会导致函数提前终止! 在C++构造函数中,既需要分配内存,又需要抛出异常时要特别注意防止内存泄露的情况发生.因为在构造函数中抛出异常,在概念上 ...

  5. 构造函数失败_抛出异常

    网上比较经典的总结: 什么函数都有可能失败,构造函数也不另外,比如new一个对象或空间不成功.当构造函数失败的时候,其实很多时候我们不想这个对象被继续生成,这个时候就可以在构造函数里面抛出异常.C++ ...

  6. C++11 委托构造函数

    1.简介 委托构造函数(Delegating Constructor)由 C++11 引入,是对 C++ 构造函数的改进,允许构造函数通过初始化列表调用同一个类的其他构造函数,目的是简化构造函数的书写 ...

  7. C++中构造函数和析构函数

    [注]致力于将知识讲明白!不懂请留言! 构造函数 定义 它是一种特殊的方法.主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中. 另外,一个类可以有 ...

  8. C++构造函数与析构函数

    几乎所有的面向对象的编程语言都保护构造函数与析构函数,好学者就要举手了,啥情况啊,Java里面不就没有析构函数嘛.好吧,你问倒我了,不过可以认为Java的垃圾自动回收机制实现了对象析构的功能.管他呢, ...

  9. java new的是构造函数_Java构造函数

    构造函数的定义: 构造函数 ,是一种特殊的方法.主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中.特别的一个类可以有多个构造函数 ,可根据其参数个 ...

最新文章

  1. 关于XAMPP环境配置
  2. Android Wifi开发之WifiConfiguration
  3. GVA gin vue从后端接口获取多选下拉框数据
  4. matlab绘制贝叶斯曲线,Matlab建立SVM,KNN和朴素贝叶斯模型分类绘制ROC曲线
  5. mysql部署策略_MySQL延迟问题和数据刷盘策略流程分析
  6. 额外参数_Pytorch获取模型参数情况的方法
  7. 计算机中专专业是什么意思,计算机专业的中专与大专有什么不同?
  8. 深度优先搜索——迷宫(洛谷 P1605)
  9. java中enum类型的使用
  10. 【易实战】Spring Cloud Greenwich Hystrix:服务容错保护
  11. 那些年关于JavaWeb的点点滴滴,你想看的这里全都有噢~
  12. 电子科技大学格拉斯哥学院英文教材使用效果
  13. UVA - 1427 Paradev单调队列
  14. 【萧蕊冰】ui设计和交互设计的区别是什么?
  15. apatch zipoutputstream 进行解压缩时提示:不可预料的压缩文件末端
  16. Aurix 多核链接文件 lsl --- 上篇
  17. laravel开源版华登区块狗
  18. JS jQuery 赋值取值整理
  19. 流动模型、物质导数与速度散度的物理意义
  20. 20170916导出fuck 7654导航

热门文章

  1. 以Chef和Ansible为例快速入门服务器配置
  2. Kafka 学习笔记之 架构
  3. SS不能在Win7中打开,出现停止运行
  4. file-max与ulimit的设置,nginx 500错误的原因
  5. html5扫面二维码逻辑
  6. 获取网络图片并异步更新UI
  7. 过程改进的疑惑 - 习惯能改么?
  8. Python 程序员必知必会的开发者工具
  9. 批量修改文本文件编码GB18030为UTF-8
  10. Ubuntu 开发者工具中心 Ubuntu Make