【中级】C++析构函数抛出异常

2024-06-21 11:38

本文主要是介绍【中级】C++析构函数抛出异常,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

C++标准指出不能在析构函数里面抛出异常!理由呢?

理由一:可能造成资源泄露!

请看如下代码:

#include <stdio.h>class A
{
public:~A(){printf("~A()\n");}
};class SuperBase
{
public:~SuperBase(){printf("~SuperBase()\n");}
};class Base : public SuperBase
{
public:Base(){pi = new int;}~Base(){throw 0;printf("deleting pi.\n");delete pi;}
private:int *pi;A a;
};int main()
{try{Base base;}catch(...){printf("catch block.\n");}return 0;
}

输出是:

~A()
~SuperBase()
catch block.

可见在异常发生时,跟异常对象(base)相关的对象(a,base的SuperBase成分)的析构函数被调用,以释放资源,这如C++标准所说。不过,base对象中pi所指向的动态内存却并未释放,造成了内存泄露。那我们把Base的析构函数改成下面这样,

~Base()
{printf("deleting pi.\n");delete pi;throw 0;
}

这样内存泄露问题不就解决了!这是不是意味着C++标准有问题,因为至少在这里抛出异常没造成什么副作用!看看下面的理由。

理由二:可能造成程序异常退出!
假设Base的析造函数已经改成上面的样子,执行以下代码看看!

int main()
{try{Base base0;Base base1;}catch(...){printf("catch block.\n");}printf("get here.\n");return 0;
}


贴上在g++中的输出:

deleting pi.
~A()
~SuperBase()
deleting pi.
~A()
~SuperBase()
terminate called after throwing an instance of 'int'This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

可见在异常发生时对象相关的资源都被释放了,因为相应的析构函数被调用了,动态分配的内存被释放了!可是异常却没有得到处理!在try块中明明把会抛出异常的代码给包围了,发生异常时却并未进入catch块中!因为并未输出“catch block.”,我们可以断定程序在try块中异常退出!为什么?

因为C++的异常处理模型不能同时处理两次以上的异常!如果两个以上的异常同时抛出,那么程序就调用terminate()函数自杀,这种情况是极难调试的!那么我们try块里面的代码抛出了几次异常?答案是2次。在try块的结尾处,首先会执行base1.Base::~Base(),在其中抛出了异常,此时程序会找匹配的catch块,在这里我们提供了一个,因此可以找到,在进入catch块之前,try块中在异常发生前创建的局部对象必须被销毁,因此又会调用base0.Base::~Base(),在其中又抛出了异常,此时程序中有2个未被处理的异常,因此调用terminate()结束程序。这也就限制了Base对象放到数组,vector,list等容器中,所以要避免在析构函数中抛出异常,如果析构函数中调用的函数可能会抛出异常,可以选择在析构函数内部把这些异常处理掉,像下面这样:

Base::~Base()
{try{call functions throwing exception.}catch(...){}
}



 


 



 


 

这篇关于【中级】C++析构函数抛出异常的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1081122

相关文章

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

Python函数作用域与闭包举例深度解析

《Python函数作用域与闭包举例深度解析》Python函数的作用域规则和闭包是编程中的关键概念,它们决定了变量的访问和生命周期,:本文主要介绍Python函数作用域与闭包的相关资料,文中通过代码... 目录1. 基础作用域访问示例1:访问全局变量示例2:访问外层函数变量2. 闭包基础示例3:简单闭包示例4

Python中isinstance()函数原理解释及详细用法示例

《Python中isinstance()函数原理解释及详细用法示例》isinstance()是Python内置的一个非常有用的函数,用于检查一个对象是否属于指定的类型或类型元组中的某一个类型,它是Py... 目录python中isinstance()函数原理解释及详细用法指南一、isinstance()函数

python中的高阶函数示例详解

《python中的高阶函数示例详解》在Python中,高阶函数是指接受函数作为参数或返回函数作为结果的函数,下面:本文主要介绍python中高阶函数的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录1.定义2.map函数3.filter函数4.reduce函数5.sorted函数6.自定义高阶函数

Python中的sort方法、sorted函数与lambda表达式及用法详解

《Python中的sort方法、sorted函数与lambda表达式及用法详解》文章对比了Python中list.sort()与sorted()函数的区别,指出sort()原地排序返回None,sor... 目录1. sort()方法1.1 sort()方法1.2 基本语法和参数A. reverse参数B.

C++读写word文档(.docx)DuckX库的使用详解

《C++读写word文档(.docx)DuckX库的使用详解》DuckX是C++库,用于创建/编辑.docx文件,支持读取文档、添加段落/片段、编辑表格,解决中文乱码需更改编码方案,进阶功能含文本替换... 目录一、基本用法1. 读取文档3. 添加段落4. 添加片段3. 编辑表格二、进阶用法1. 文本替换2

Python异常处理之避免try-except滥用的3个核心原则

《Python异常处理之避免try-except滥用的3个核心原则》在Python开发中,异常处理是保证程序健壮性的关键机制,本文结合真实案例与Python核心机制,提炼出避免异常滥用的三大原则,有需... 目录一、精准打击:只捕获可预见的异常类型1.1 通用异常捕获的陷阱1.2 精准捕获的实践方案1.3

C++中处理文本数据char与string的终极对比指南

《C++中处理文本数据char与string的终极对比指南》在C++编程中char和string是两种用于处理字符数据的类型,但它们在使用方式和功能上有显著的不同,:本文主要介绍C++中处理文本数... 目录1. 基本定义与本质2. 内存管理3. 操作与功能4. 性能特点5. 使用场景6. 相互转换核心区别

Python函数的基本用法、返回值特性、全局变量修改及异常处理技巧

《Python函数的基本用法、返回值特性、全局变量修改及异常处理技巧》本文将通过实际代码示例,深入讲解Python函数的基本用法、返回值特性、全局变量修改以及异常处理技巧,感兴趣的朋友跟随小编一起看看... 目录一、python函数定义与调用1.1 基本函数定义1.2 函数调用二、函数返回值详解2.1 有返