什么函数都有可能失败,构造函数也不另外,比如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:
for(int i=0;i<10;i++)
str[i]=NULL; //对str[]初始化,这是必须的,不然再后面delete就会出现问题
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, 这才是构造函数抛出去的异常,外层会扑捉到,并且析构函数不会被调用
for(int i=0;i<10;i++)
delete []str[i];
int main()
A *pA=NULL;
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中常见。
转自:http://blog.csdn.net/wind19/article/details/8213114
构造函数中抛出的异常
1、标准C++中定义构造函数是一个对象构建自己,分配所需资源的地 方,一旦构造函数执行完毕,则表明这个对象已经诞生了,有自己的行为和内部的运行状态,之后还有对象的消亡过程(析构函数的执行)。可谁能保证对象的构造 过程一定能成功呢?说不定系统当前的某个资源不够,导致对象不能完全构建好自己(人都有畸形儿,更何况别的呢?朋友们!是吧!),因此通过什么方法来表明
基本技能 12.4:动态内存分配
C++程序中有两种主要的方式用于在内存中存储数据。第一种就是通过使用变量。变量的存储空间是在编译时就分配好的,在程序运行时是不可改变的。第二种方式就是通过C+的动态内存分配机制来进行内存分配。在这种方式中,数据存储空间是在程序需要的时候由系统从位于程序代码区和栈区之间的空
什么函数都有可能失败,构造函数也不另外,比如new一个对象或空间不成功。当构造函数失败的时候,其实很多时候我们不想这个对象被继续生成,这个时候就可以在构造函数里面抛出异常。C++规定构造函数抛出异常之后,对象将不被创建,析构函数也不会被执行,但已经创建成功的部分(比如一个类成员变量)会被部分逆序析构,不会产生内存泄漏。但有些资源需要在抛出异常前自己清理掉,比如打开成功的一个文件,最好关闭掉再抛出异
能在构造函数中抛出异常,然后在外面捕获吗?
可以,但不建议这样做。C++之父和herb sutter这样的最顶级专家建议不要把容易出错的代码放在构造函数中,当然如果非要在构造函数做一些容易失败的事,那就在构造里throw异常吧。另外对于析构函数,Herb Sutter在Exceptional c++ 中也说过说:“...
问题概述:
编译插件代码,cmake和make均成功,但是执行sudo make install时报错cannot find -lclass_loader,在CMakeLists.txt中添加find_package(class_loader),cmake时提示可以找到class_loader,但是make install 还是报错。
解决方案:
修改系统时间 sudo date -s “YYYY/MM/DD HH:mm:ss”。
问题概述:
pm_test中起线程执行pm
构造子类对象的时候,在进入子类构造函数之前会先调用父类的构造函数。 如果没有显式调用父类构造函数就会调用默认的父类构造函数。但是你的父类又没有默认构造函数所以自然会出错。 3。几种修改方法: a。父类中重载构造函数,一个有参数,一个没参数。 class a { a(int a, int b, int c);
C++ 构造函数的异常是一个比较难缠的问题,很多时候,我们可能不去考虑这些问题,如果被问到,有人可能会说使用RAII管理资源。
但你真的考虑过如果构造函数失败了,到底会发生什么吗,前面构造成功的成员、基类对象应该怎样回收?
最近在知乎上看到有人提到这个问题:
http://www.zhihu.com/question/22889420
看了陈硕的回答,抱着怀疑的心态写代码加以验证。
...
构造函数中可不可以抛出异常?当然可以。从语法上来说,是可以的;从实际情况来看,现在的软件系统日渐庞大和复杂,很难保证 Constructor 在执行过程中完全不发生一点异常。
那么,如果构造函数中抛出异常,会发生什么情况呢?
一、构造函数中抛出异常将导致对象的析构函数不被执行。
C++仅能 delete 被完全构造的对象(fully constructed ...