C++构造函数抛出异常需要注意的地方

 更新时间:2020年08月15日 09:51:32   作者:Dabelv  
这篇文章主要介绍了C++构造函数抛出异常需要注意的地方,帮助大家更好的理解和学习c++,感兴趣的朋友可以了解下

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

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生命周期结束时被调用,避免了资源泄漏。

以上就是C++构造函数抛出异常需要注意的地方的详细内容,更多关于C++构造函数的资料请关注脚本之家其它相关文章!

相关文章

  • C语言版飞机大战游戏

    C语言版飞机大战游戏

    这篇文章主要为大家详细介绍了C语言版飞机大战游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-12-12
  • 详解C++中const_cast与reinterpret_cast运算符的用法

    详解C++中const_cast与reinterpret_cast运算符的用法

    这篇文章主要介绍了C++中const_cast与reinterpret_cast运算符的用法,经常被用于表达式中的类型转换,需要的朋友可以参考下
    2016-01-01
  • 利用C语言实现将格式化数据和字符串相互转换

    利用C语言实现将格式化数据和字符串相互转换

    这篇文章主要为大家详细介绍了2个函数,分别是sprintf和sscanf,可以用来实现将格式化数据和字符串相互转换,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-03-03
  • c++标准输入输出流关系的前世今生

    c++标准输入输出流关系的前世今生

    这篇文章主要给大家介绍了关于c++标准输入输出流关系的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • C语言实现进制转换函数的实例详解

    C语言实现进制转换函数的实例详解

    这篇文章主要介绍了C语言实现进制转换函数的实例详解的相关资料,这里提供实现实例帮助大家实现改功能,需要的朋友可以参考下
    2017-08-08
  • C语言实现opencv提取直线、轮廓及ROI实例详解

    C语言实现opencv提取直线、轮廓及ROI实例详解

    这篇文章主要介绍了C语言实现opencv提取直线、轮廓及ROI实例详解,具有一定借鉴价值,需要的朋友可以参考下
    2018-01-01
  • C++函数重载详解及实例代码

    C++函数重载详解及实例代码

    这篇文章主要介绍了C++函数重载详解及实例代码的相关资料,需要的朋友可以参考下
    2016-09-09
  • C++11实现简易定时器的示例代码

    C++11实现简易定时器的示例代码

    这篇文章主要介绍了C++11实现简易定时器的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04
  • C语言利用UDP实现群聊聊天室的示例代码

    C语言利用UDP实现群聊聊天室的示例代码

    UDP是一个轻量级、不可靠、面向数据报的、无连接的传输层协议,多用于可靠性要求不严格,不是非常重要的传输,如直播、视频会议等等。本文将利用UDP实现简单的群聊聊天室,感兴趣的可以了解一下
    2022-08-08
  • C++实现动态线性表

    C++实现动态线性表

    这篇文章主要为大家详细介绍了C++实现动态线性表,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-05-05

最新评论