网上比较经典的总结:

什么函数都有可能失败,构造函数也不另外,比如new一个对象或空间不成功。当构造函数失败的时候,其实很多时候我们不想这个对象被继续生成,这个时候就可以在构造函数里面抛出异常。C++规定构造函数抛出异常之后,对象将不被创建,析构函数也不会被执行,但已经创建成功的部分(比如一个类成员变量)会被部分逆序析构,不会产生内存泄漏。但有些资源需要在抛出异常前自己清理掉,比如打开成功的一个文件,最好关闭掉再抛出异常(虽然系统也会把这个资源回收),因为抛出异常之后析构函数不会被执行了。

(1) C++中通知对象构造失败的唯一方法那就是在构造函数中抛出异常;(这句话并不是说我们只有这个方法才能让上层知道构造函数失败,虽然构造函数没有返回值,我们完全可以在构造函数中传入一个引用值,然后在里面设置状态,运行完构造函数之后任然可以知道是否失败,但这种情况下面对象其实还是被构造出来的,只是里面有资源分配失败而已,并且析构函数还是会执行。这和我们构造失败不生成对象的初衷不符。)

  (2) 构造函数中抛出异常将导致对象的析构函数不被执行;(但已经生产的部分成员变量还是会被逆向析构的)
  (3) 当对象发生部分构造时,已经构造完毕的子对象将会逆序地被析构;

网上的一个栗子:

一个实例对象的构造:
第一步,分配足够的内存,如果失败就是栈溢出或抛出std::bad_alloc的异常,所以在这步你不用担心内存泄露,而且这一步你是不能插手的,如果这步成功,就进入第二步。

new运算符的实现保证了内存泄漏不会发生。例如

T *p = new T;

将被编译器转换给类似下面的样子:(其实和我们自己释放已经申请的资源的思想流程是一样的)

// 第一步,分配原始内存,若失败则抛出bad_alloc异常
try {// 第二步,调用构造函数构造对象new (p)T;       // placement new: 只调用T的构造函数
}
catch(...) {delete []p;     // 释放第一步分配的内存throw;          // 重抛异常,通知应用程序
}

第二步,调用构造函数,在通常情况下,如果构造函数为空或没有进行动态内存分配,你就不用关心内存泄露了
你需要关心的是构造函数中有动态内存分配

class A
{char* str[10];
public:A(){for(int i=0;i<10;i++)str[i]=NULL;     //对str[]初始化,这是必须的,不然再后面delete就会出现问题try{for(int i=0;i<10;i++)str[i]=new char[1024*1024*1024];   //要来就来狠的
    }catch(bad_alloc){for(int i=0;i<10;i++)delete []str[i];  //放心,即使delete NULL是不会出问题的throw;  //就抛出这个bad_alloc, 这才是构造函数抛出去的异常,外层会扑捉到,并且析构函数不会被调用
    }}~A(){for(int i=0;i<10;i++)delete []str[i];         }
};
int main()
{A *pA=NULL;try{pA=new A;}catch(bad_alloc){cout<<"Out of memory"<<endl;}delete pA;return 0;
}

pA是用NULL初始化的,即使在给A分配内存时(第一步)失败,也不会导致后面的delete pA出错。

对于构造函数可能失败的做法一般有两种

1. 在构造函数中抛出异常,本对象构造未完成,它的析构函数不会被调用。当然,我们有义务释放已经分配到的资源。简单,最常见。
2. 把资源的初始化工作放在另一个单独函数中,比如 bool init(...),由对象创建者(比如工厂方法)先调用构造函数,再调用init方法。ATL中常见。

转载于:https://www.cnblogs.com/Lunais/p/5674123.html

构造函数失败_抛出异常相关推荐

  1. android+jni+构造函数,在JNI中调用构造函数失败Android

    我想从我的JNI Android代码调用构造函数;但不知何故,它失败,以下例外.. 我相信我失去了一些非常小的东西;但我无法弄清楚......任何人都可以请指出?在JNI中调用构造函数失败Androi ...

  2. electron下载失败_解决方案汇总

    文章目录 electron下载失败_解决方案汇总 `node install.js` 出错 `RequestError: connect ETIMEDOUT 20.205.243.166:443` ` ...

  3. 2021-10-27 Vue安装脚手架npm install -g @vue/cli命令失败_因为文件已存在

    这里写自定义目录标题 Vue安装脚手架npm install -g @vue/cli命令失败_因为文件已存在 Vue安装脚手架npm install -g @vue/cli命令失败_因为文件已存在 1 ...

  4. @autowired失败_@Autowired的使用:推荐对构造函数进行注释

    在编写代码的时候,使用@Autowired注解是,发现IDE报的一个警告,如下: Spring Team recommends "Always use constructor based d ...

  5. c++ 构造函数数组_从 JS 数组操作到 V8 array.js

    前言 最近在写面试编程题,经常用到数组,经常想偷个懒,用它提供的方法,奈何还是对数组方法使用不熟练,导致写了很多的垃圾代码,很多地方稍加修改的话肯定变得简洁高效优雅? 所以✍这篇文章本着了解一下Jav ...

  6. rust语法丑陋_抛出异常–缓慢而丑陋

    rust语法丑陋 这篇文章是关于历史经验以及最近应用的性能优化技术的. 几年前,我在特定的应用程序中发誓,我不得不发现隐藏在真正聪明的工程"技术"之下的无证行为. 它是负责开票的典 ...

  7. 护士资格证延续注册WEB服务调用失败_服务熔断

    熔断机制是应对服务雪崩效应的一种微服务链路保护机制,当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回"错误"的响应信息.当检测 ...

  8. 2 安装失败_写bug日记2:PYTORCH GEOMETRIC安装失败的问题(未解决)

    报错信息: import torch_sparse 返回 OSError: libcusparse.so.10: cannot open shared object file: No such fil ...

  9. c++ 构造函数数组_“动态数组”的设计与实现

    引言 数据结构是计算机存储.组织数据的方式.常见的数据结构有: (1)线性结构 如:线性表(包括:数组.链表.栈.队列.哈希表). (2)树形结构 如:二叉树.AVL树.红黑树.B树.堆.Trie.哈 ...

最新文章

  1. linux文件权限详解
  2. 纳米片晶体管是摩尔定律的下一步,也许是最后一步!
  3. TOJ 3750: 二分查找
  4. IOS --自带二维码扫描
  5. 学java时的一些笔记(2)
  6. Asp.Net 中使用客户端Activex控件需要注意的事情
  7. 在c++使用文件流(初学者必看)
  8. Sublime Text
  9. 使用DiskFileItemFactory 实现文件上传 ,设定缓冲区大小和存放临时文件目录。
  10. codeforces 1017E
  11. C#中使用DES和AES加密解密
  12. 回头看看的时候openeim001
  13. FreeMarker三宗罪!
  14. [Matlab] 传入 dsolve 的方程组必须是行向量才能求解
  15. Centos6.x 64位 安装JDK
  16. 5.PHP ES 使用
  17. tensorflow+python flask进行手写识别_Flask发布模型2
  18. C语言六种方法求素数(质数) 最全 输出2-100以内的所有素数 求1000以内的所有素数
  19. WGS84坐标系-地心地固坐标系-东北天坐标系
  20. PTGUI 全景图批量拼接

热门文章

  1. hibernate实战第二版 蒲成带目录_太NB了! 阿里程序员带你玩转Spring:脑图+实战五+面试百问+知识总结...
  2. java绘制半透明图片_如何使绘制的图像在Java中透明
  3. linux csi驱动添加,CSI接口Camera驱动学习
  4. Arduino笔记-解决上传时出现avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0x00问题
  5. 前端笔记-使用vue-cli(脚手架)开发TodoList
  6. Java高级语法笔记-库的使用(jar)
  7. Java基础入门笔记-添加包
  8. 大三软件工程小项目-小技术集合总结
  9. DJS_130小型计算机,我收藏的中国第一台计算机djs-130的操作系统纸带
  10. java 验证码_如何使用Java生成随机验证码