条款08: 别让异常逃离析构函数

news2024/11/27 22:27:55

文章目录

    • 背景知识
    • 析构函数

背景知识

下面是一段测试代码:

class Test
{
public:
    Test(int para){m_num = para;};
    void test_throw(){throw(3);};
    ~Test() {cout<<"delete Test="<<m_num<<endl;
    //test_throw();
    };
    int m_num;
};
int main() {
    try {
        Test t1(1);
        throw(1);
        Test t2(2);
    }
    catch(...) {
        cout<<"catch except"<<endl;
    }
    return 0;
}
  • 在try的代码块里,一旦某一行抛出异常,那么该行后的代码就不会执行
  • try的代码块作用域结束时,前面对象会调用析构函数

输出结果验证上面的结论
在这里插入图片描述

  • 如果一个try的代码块抛出两个异常,但是catch只能抓住一个,然而标准说:throw will always call terminate()程序就会自动停止。

把上面的test_throw()注释掉就可以了,注意这里直接在析构函数里写throw, C++11在编译的时候会给提醒,所以索性弄一个函数包装一些。

在这里插入图片描述

析构函数

  1. 根据上面的说明,一般对象在作用域抛出异常后还是要析构的,一旦该对象在析构时再次抛出异常,就会导致程序终止,异常捕获将失去了意义。
  2. 假如只有析构函数抛出异常,比如try中有三个对象,第一个对象析构抛出异常后,后面的第二个对象再抛出异常一样会导致程序终止(书上说会也有可能导致不确定行为,gcc4.6.4复现的结果是直接终止)

注意,在C++11中,析构函数默认是noexcept的,一个noexcept的函数一旦抛出异常,程序就会直接终止的,所以目前C++11中,该条目已经有点过时了,但是下面的设计思路还是要掌握的。

class DBConnection
{
public: 
	~DBConnection()
	{
		db.close();
	}
private:
	DB db;
}

上面的代码,当析构失败的时候,析构函数就会把异常往外抛。C++11中会直接终止程序。

class DBConnection
{
public: 
	~DBConnection()
	{
		try
		{
			db.close();
		}
		catch(...)
		{
			std::abort();
		}
	}
private:
	DB db;
}

上述代码可以直接捕获异常,强制结束程序,不让你出现继续运行的可能。
还有一种是书上推荐的方案,在paddle框架的代码中也看到了相关设计理念paddle/fluid/memory/allocation/mmap_allocator.cc:166L, 具体实现如下:

class DBConnection
{
public: 
	void Close()
	{
		db.close();
		closed = true;
	}
	~DBConnection()
	{
		if(!colsed)
		{
			try
			{
				db.close();
			}
			catch(...)
			{
				std::abort();
			}
		}
	}
private:
	DB db;
	bool closed;
}

为什么这样设计,因为析构函数是noexcept(这里不考虑C++98),异常会导致程序终止,而其他函数抛出异常则还有抢救机会,比如如果close抛出异常会是一个确定的数字1,那么当你收到异常1你作为用户可以设置相应的处理方案,忽略或者关机或者再次尝试。相比之下用户自己定义一个close更好。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/423477.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

牛客乔迁新居,新址在……

有个好消息想向大家公布&#xff1a;牛客&#xff08;上海办公室&#xff09;搬家啦&#xff01; 自3月27日起&#xff0c;牛客&#xff08;上海办公室&#xff09;正式乔迁至上海市长宁区长宁路999号兆丰广场办公楼G层G15。新的办公室坐落在上海长宁区的中心地带&#xff0c;…

Talk预告 | 浙江大学特聘研究员廖依伊:面向自动驾驶仿真平台的神经渲染

本期为TechBeat人工智能社区第477期线上Talk&#xff01; 北京时间3月1日(周三)20:00&#xff0c;浙江大学信电学院特聘研究员——廖依伊的Talk将准时在TechBeat人工智能社区开播&#xff01; 她与大家分享的主题是: “面向自动驾驶仿真平台的神经渲染”&#xff0c;届时将探…

VSCode 配置PyQt5 开发环境

前提要求&#xff1a;Windows 安装Anaconda。 如果没有安装&#xff0c;请参考文章:Windows安装Anaconda使用教程 1、PyQt 5 安装 在配置python环境的时候需要注意&#xff0c;PyQt5需要python 3.5以上的版本&#xff0c;在python环境中(conda、pipenv)安装pyqt5相关组件Py…

4.13(LoadLibrary)

接着之前预习的知识&#xff0c;我观察的自己编译出来的bin LoadLibraryExA LoadLibraryExA函数进去&#xff0c;现时用RtInitAnsiString函数初始化了ANSI的计数字符串&#xff0c;底层是调用了LoadLibraryExW函数&#xff0c;在LoadLibrarExW函数里做了unicode的计数字符串的…

分子生物学 第三章 基因、基因组及基因组学

文章目录第三章 基因、基因组及基因组学第一节 基因1 基因认识的三个阶段2 基因的特征(1)跳跃基因(2)断裂基因3 基因的分类4 基因的结构5 基因的大小6 基因的数目第二节 基因组1 基因组的概念2 噬菌体基因组3 细菌基因组以大肠杆菌(原核生物的代表)为研究对象4 酵母基因组以酵母…

Python之拯救Xubuntu22.04误删/usr/bin/python3.10(二十二)

0.首先删除/usr/bin/python3.10,会导致以下错误: <1>.报错1: ModuleNotFoundError: No module named ‘apt_pkg’ <2>.报错2: bash: /usr/lib/command-not-found: /usr/bin/python3: 解释器错误: 没有那个文件或目录 <3>.报错3: 通过亲身操作,以下步骤可…

【Linux】来写一个tcp的服务端+客户端

本文首发于 慕雪的寒舍 今天让我们来写一个tcp的服务器/客户端代码。 完整代码见我的gitee 链接 阅读本文前&#xff0c;建议先阅读&#x1f449; udp服务器 由于本文采用自建图床&#xff0c;CSDN可能因带宽不够&#xff0c;出现外链图片缓存失败。 1.基本框架 tcp的服务器…

walt 调度算法

Walt 算法 WALT负载统计原理_walt算法_森森浅浅笙笙的博客-CSDN博客 CPU负载均衡之WALT学习【转】_mb5fdcad0be2e90的技术博客_51CTO博客 1、A task’s demand is the maximum of its contribution to the most recently completed window and its average demand over the p…

webgl-attribute、uniform、varying三者的区别

通用js: let canvas document.getElementById(webgl) canvas.width window.innerWidth canvas.height window.innerHeight let ctx canvas.getContext(webgl) attribute&#xff1a; 范围: 只适用于vertexShader&#xff0c;将js代码中的数据传递给vertexShader。 使用方…

知识图谱扩充|蜕变测试|蜕变关系

目录 前言&#xff1a;概念定义 什么是蜕变测试&#xff1f; 那么&#xff0c;怎么进行蜕变测试呢&#xff1f; 1. 生成蜕变关系 a 等价关系 b 混排关系 c 交集关系 d 并集关系 2. 生成蜕变用例 3. 执行蜕变用例 4. 校验蜕变关系 学术报告 一、蜕变测试MT 二、蜕变…

【id:32】【20分】B. Date(类与构造)

题目描述 下面是一个日期类的定义&#xff0c;请在类外实现其所有的方法&#xff0c;并在主函数中生成对象测试之。 注意&#xff0c;在判断明天日期时&#xff0c;要加入跨月、跨年、闰年的判断 例如9.月30日的明天是10月1日&#xff0c;12月31日的明天是第二年的1月1日 2月…

vue2路由(下)

编程式路由导航 通过点击按钮实现push和replace俩种模式的跳转 实现&#xff1a;就是通过$router原型里面的方法 也能实现路由的跳转和后退&#xff0c;分别采用的是$router里面的black和forward方法 感觉就是BOM对象中的history对象里面的方法 正是前进&#xff0c;后是后…

快鲸scrm | 三个步骤,快速打造企业长效私域营销阵地

快鲸scrm对企业微信私域流量玩法进行系统梳理&#xff0c;把企业微信用户运营拆解为“获客”、“转化”和“服务”这三个关键步骤&#xff0c;从点到面&#xff0c;为企业私域运营提供可行性的解决方案。 一、构建私域流量管理机制 用户是企业发展的基础&#xff0c;用户增长对…

三电技术之电控技术

三电技术之电控技术 1 基本功能 整车控制系统能够实现对汽车动力、舒适度、安全性以及能耗等多方面进行调整优化&#xff0c;配合大数据让电动汽车拥有更好的操作性和可靠性&#xff0c;具体来讲整车控制器对电动汽车主要有以下功能&#xff1a; 数据交互管理&#xff1a;整…

mybatis-plus-join MPJ连表查询 这样写太香了!

mybatis-plus作为mybatis的增强工具&#xff0c;它的出现极大的简化了开发中的数据库操作&#xff0c;但是长久以来&#xff0c;它的联表查询能力一直被大家所诟病。一旦遇到left join或right join的左右连接&#xff0c;你还是得老老实实的打开xml文件&#xff0c;手写上一大段…

【unity实战】用对象池设计制作Dash冲锋残影的效果

什么是对象池? 在Unity中,对象池是一种重复使用游戏对象的技术。使用对象池的好处是可以减少游戏对象的创建和销毁,从而提高游戏的性能。如果不使用对象池,每次需要创建游戏对象时,都需要调用Unity的Instantiate函数,这会导致内存分配和垃圾回收的开销。而使用对象池,可…

李宏毅 深度学习【持续更新】

目录pytorch快速入门csdn快速入门OS包PIL包Opencv包Dataset类Tensorboard的使用torchvision.transforms 的使用torchvision中数据集的使用DataLoader的使用(torch.utils.data)神经网络的搭建nn.Module深度学习 李宏毅Chatgpt1 研究方向2 Chatgpt学习的步骤3 Fine tune vs. Prom…

【Linux内网穿透】使用SFTP工具快速实现内网穿透

文章目录内网穿透简介1. 查看地址2.局域网测试连接3.创建tcp隧道3.1. 安装cpolar4.远程访问5.固定TCP地址内网穿透简介 是一种通过公网将内网服务暴露出来的技术&#xff0c;可以使得内网服务可以被外网访问。以下是内网穿透的一些应用&#xff1a; 远程控制&#xff1a;通过内…

九【springboot】

Springboot一 Spring Boot是什么二 SpringBoot的特点1.独立运行的spring项目三 配置开发环境四 配置开发环境五 创建 Spring Boot 项目1.在 IntelliJ IDEA 欢迎页面左侧选择 Project &#xff0c;然后在右侧选择 New Project&#xff0c;如下图2.在新建工程界面左侧&#xff0c…

深入理解PyTorch中的train()、eval()和no_grad()

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️&#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…