C++:异常处理

异常处理中对象参数与引用参数的选择

User:

  • catch()中的参数如果使用基类的引用,是不是相当于声明了一个引用,它是基类类型的,catchthrow的抛出的对象之后,就相当于这个基类引用指向了抛出的对象?

ChatGPT:

  • 是的,你说得很对。当在 catch 块中使用基类的引用作为参数时,相当于声明了一个引用,它是基类类型的。当程序抛出一个异常并且在调用栈中找到匹配的 catch 块时,如果异常的类型与 catch 块中指定的引用类型相匹配,那么这个引用会指向被抛出的异常对象
    这样做的好处是可以使用基类的引用来捕获派生类对象的异常,从而实现多态性。因为派生类对象也是基类对象,所以可以使用基类的引用来引用它们,从而实现了异常处理时的多态性。

User:

  • 如果 catch 中的参数不是引用,而是一个对象呢?情况将会是如何的?

ChatGPT:

  • 如果在 catch 块中的参数不是引用,而是一个对象,那么将会发生对象的拷贝。这意味着异常对象会被复制一份,而不是通过引用来访问原始的异常对象。
    具体来说,当抛出异常并且在调用栈中找到匹配的 catch 块时,如果异常的类型与 catch 块中指定的对象类型相匹配,那么会发生对象的拷贝,即异常对象的副本会被创建并传递给 catch 块。
    这种情况下,与使用引用相比,会产生额外的开销,因为需要进行对象的拷贝操作。通常情况下,建议在异常处理中使用引用而不是对象,以避免不必要的对象拷贝。

User:

  • 如果是这样,那么整个过程将会产生两次复制构造,一次是 throw,一次是 catch,对吗?

ChatGPT:

  • 是的,你说得对。如果在 catch 块中的参数是一个对象而不是引用,那么整个过程将会产生两次复制构造。
    因此,使用对象作为 catch 块的参数会导致两次复制构造,增加了额外的开销。相比之下,使用引用作为 catch 块的参数可以避免这种额外的开销,因为引用不会引发对象的复制,而是直接引用原始的异常对象。

可以看到 GPT 的回答很好,以下是我写得一个实例,来解释以上的所有信息:

#include <iostream>
#include <string>int a = 0;class Base {int data;public:Base(int d = 0) : data(d) {}virtual ~Base() { std::cout << "Base destructor called.\n" << std::endl; }virtual void display() const {std::cout << "Base base value:" << data << "\n" << std::endl;}int value() const { return data; }// 复制构造Base(const Base &other) : data(other.data) {a++;std::cout << "Base copy constructor called.\n" << std::endl;}
};class Derived : public Base {char data;public:Derived(char c = 'a') : Base(), data(c) {}virtual ~Derived() {std::cout << "Derived destructor called.\n" << std::endl;}virtual void display() const override {std::cout << "Derived base value:" << Base::value() << std::endl;std::cout << "Derived derived value:" << data << "\n" << std::endl;}// 复制构造Derived(const Derived &other) : Base(other), data(other.data) {a++;std::cout << "Derived copy constructor called.\n" << std::endl;}
};void throwException(bool useDerived) {if (useDerived) {Derived d('b');throw d;} else {Base b(100);throw b;}
}int main() {try {// 使用基类的引用捕获异常// 调用一次基类复制构造+1// 调用一次派生类复制构造+1// 析构抛出对象try {std::cout << "---------------开始构造--------------" << std::endl;throwException(true);} catch (Base &b) {std::cout << "\na: " << a << std::endl;b.display(); // 多态调用// 生命周期结束,析构指向的对象std::cout << "---------------开始析构--------------" << std::endl;}// 调用一次基类复制构造+1// 调用一次派生类复制构造+1// 析构抛出对象// 由于catch()参数是对象// 继续调用基类复制构造+1try {std::cout << "---------------开始构造--------------" << std::endl;throwException(true);} catch (Base b) {std::cout << "\na: " << a << std::endl;b.display(); // 非多态调用,发生切片现象// 生命周期结束,析构临时对象,以及 bstd::cout << "---------------开始析构--------------" << std::endl;}// 调用一次基类复制构造+1// 析构抛出对象try {std::cout << "---------------开始构造--------------" << std::endl;throwException(false);} catch (Base &b) {std::cout << "\na: " << a << std::endl;b.display();// 生命周期结束,析构指向的对象std::cout << "---------------开始析构--------------" << std::endl;}// 调用基类复制构造+1// 析构抛出对象// 由于 catch()参数是对象// 调用复制构造+1try {std::cout << "---------------开始构造--------------" << std::endl;throwException(false);} catch (Base b) {std::cout << "\na: " << a << std::endl;b.display();// 生命周期结束,析构临时复制对象,以及 bstd::cout << "---------------开始析构--------------" << std::endl;}} catch (const std::exception &e) {std::cerr << "\nCaught exception: " << e.what() << std::endl;}return 0;
}

运行结果:

./main                      
---------------开始构造--------------
Base copy constructor called.Derived copy constructor called.Derived destructor called.Base destructor called.a: 2
Derived base value:0
Derived derived value:b---------------开始析构--------------
Derived destructor called.Base destructor called.---------------开始构造--------------
Base copy constructor called.Derived copy constructor called.Derived destructor called.Base destructor called.Base copy constructor called.a: 5
Base base value:0---------------开始析构--------------
Base destructor called.Derived destructor called.Base destructor called.---------------开始构造--------------
Base copy constructor called.Base destructor called.a: 6
Base base value:100---------------开始析构--------------
Base destructor called.---------------开始构造--------------
Base copy constructor called.Base destructor called.Base copy constructor called.a: 8
Base base value:100---------------开始析构--------------
Base destructor called.Base destructor called.

可以看到catch()的参数尽管可以被设为引用,但是其实仍然要发生异常对象的复制(用复制构造函数)。如果没有被设置为引用,那么在最后,不仅要析构异常对象副本,还要析构异常对象本身。

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

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

相关文章

解决FLINK CDC监控oracle报Failed to parse insert DML问题

更多优秀文章,请扫码关注个人微信公众号或搜索“程序猿小杨”添加。 一、错误展现: Caused by: io.debezium.connector.oracle.logminer.parser.DmlParserException: Failed to parse insert DML: insert into "HIS_DATA". at io.debezium.connector.oracle.logm…

Nginx内存池相关源码剖析(三)小块内存分配逻辑

在Nginx中&#xff0c;小块内存通常指的是那些大小相对较小、分配和释放频率较高的内存块。这些内存块由于数量众多、管理复杂&#xff0c;因此需要使用一种高效的内存管理机制来减少内存管理的开销和内存碎片的产生。 Nginx内存池通过一种预分配和复用的方式来管理小块内存。当…

觉飞、希亦、Daily neaty内衣洗衣机好用吗?爆款产品性能全面测评!

近几年来小家电产品中&#xff0c;内衣洗衣机的讨论热度无疑是最大的&#xff0c;功能多、操作方便&#xff0c;用内衣洗衣机来清洗内衣裤会更加卫生和安全&#xff0c;能满足了消费者的多种需求。不过尽管市面上的内衣洗衣机品牌很多、挑选空间大&#xff0c;也不是所有产品都…

RT-thread-线程间通讯3-事件集

事件集 事件集也是线程间同步的机制之一,一个事件集可以包含多个事件,利用事件集可以完成一对多,多对多的线程间同步。 一个线程和多个事件的关系可设置为: 其中任意一个事件唤醒 线程,或几个事件都到达后唤醒线程,多个事件集合可以用一个32bit无符号整型变量来表示,…

4.8-4.12算法刷题笔记

刷题 堆1. 堆排序2. 模拟堆 哈希表3. 模拟散列表4. 字符串哈希 DFS5. 排列数字6. n-皇后问题 2. BFS&#xff08;队列&#xff09;7. 字母迷宫8. 滑动谜题 3. 树与图的dfs9. 树的重心 4. 树与图的bfs(最短路)10. 图中点的层次( 无权最短路 ) 5. 拓扑排序11. 课程表 6. 朴素dijk…

人工智能时代的图像识别:机遇与挑战并存

人工智能&#xff08;AI&#xff09;时代为图像识别领域带来了前所未有的机遇&#xff0c;同时也伴随着一系列挑战。这一领域的发展不仅深刻影响了科技、医疗、教育、娱乐等多个行业&#xff0c;还在一定程度上改变了人们的生活方式。 机遇&#xff1a; 技术突破与创新&#…

prometheus.yaml

目录 一、说明1、全局配置 global&#xff1a;2、告警配置 alerting&#xff1a;3、规则文件配置 rule_files&#xff1a;4、拉取配置 scrape_configs&#xff1a;5、远程读写配置 remote_read/remote_write&#xff1a; 二、简单配置示例&#xff1a; 一、说明 prometheus的配…

GoLang核心知识点

目录 1. 系统中断信号注册 2. 通道接收多个返回值 3. go context 4. reflect 5. json字符串对象转换 1. 系统中断信号注册 interrupt : make(chan os.Signal) // 可以控制强制终止的信号 // 如果系统有中断信号&#xff0c;发送给r.interrupt signal.Notify(interrupt, os…

docker (CentOS,ubuntu)安装及常用命令

Docker和虚拟机一样&#xff0c;都拥有环境隔离的能力&#xff0c;但它比虚拟机更加轻量级&#xff0c;可以使资源更大化地得到应用 Client&#xff08;Docker客户端&#xff09;&#xff1a;是Docker的用户界面&#xff0c;可以接受用户命令&#xff08;docker build&#xff…

纯前端umi项目部署页面自动刷新

背景 在用户正在访问单页面网站的情况下&#xff0c;突然发布了新的版本。而由于单页面中路由特性&#xff0c;或浏览器缓存的原因&#xff0c;并不会随着路由变化而重新加载前端资源&#xff0c;此时用户浏览器所运行的脚本&#xff0c;并非是最新的代码&#xff0c;从而可能…

img标签图片未加载完成占位图

通过Css控制&#xff0c;实现加载接口下发或者网络图片时&#xff0c;未加载完成前&#xff0c;先加载本地一张占位图&#xff0c;记载完成显示接口下发的图或者网络图。 实现方式&#xff1a;通过在img标签的after伪元素上添加一张占位图&#xff0c;并且img标签都设置为posi…

记录Python的pandas库详解

如何生成一个pd import pandas as pd df pd.DataFrame([[1,2,3],[4,5,6]],index[A,B],columns[C1,C2,C3])df ---------------------------------------------------------------------------C1 C2 C3 A 1 2 3 B 4 5 6df.T -------------------------------------------------…

爬虫 新闻网站 以湖南法治报为例(含详细注释) V4.0 升级 自定义可任意个关键词查询、时间段、粗略判断新闻是否和优化营商环境相关,避免自己再一个个判断

目标网站&#xff1a;湖南法治报 爬取目的&#xff1a;为了获取某一地区更全面的在湖南法治报的已发布的和优化营商环境相关的宣传新闻稿&#xff0c;同时也让自己的工作更便捷 环境&#xff1a;Pycharm2021&#xff0c;Python3.10&#xff0c; 安装的包&#xff1a;requests&a…

element-ui container 组件源码分享

今日简单分享 container 组件的源码实现&#xff0c;从以下两个方面来讲解&#xff1a; 1、container 组件的页面结构 2、container 组件的属性 一、container 组件的页面结构 二、container 组件的属性 1、container 部分的 direction 属性&#xff0c;子元素的排列方向&am…

Nacos2.3.0安装部署

一&#xff0c;准备安装包 github下载点 二&#xff0c;在/usr/local/目录下创建一个文件夹用于上传和解压Nacos cd /usr/local/ #上传Nacos文件 #解压之前cd进安装包根目录 cd /usr/local/ #这边选择的Nacos版本为2.3.0 tar -zxxvf nacos-server-2.3.0.tar.gz #把该文件移动…

Spring Boot安装与配置

一、引言 Spring Boot是一个开源的Java框架&#xff0c;用于简化Spring应用的创建、运行和部署过程。它遵循“约定优于配置”的原则&#xff0c;使得开发者能够更专注于业务逻辑的实现&#xff0c;而非繁琐的配置。本教程将指导您完成Spring Boot的安装和配置过程&#xff0c;…

基于SpringBoot的“商务安全邮箱”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“商务安全邮箱”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能结构 收件箱效果图 草稿箱效果图 已发送…

【数据结构】习题之消失的数字和轮转数组

&#x1f451;个人主页&#xff1a;啊Q闻 &#x1f387;收录专栏&#xff1a;《数据结构》 &#x1f389;前路漫漫亦灿灿 前言 消失的数字这道题目我会和大家分享三种思路。 还有一道题目是轮转数组&#xff0c;&#xff0c;也会分享三种思路&#xff0c;大…

常见的垃圾回收器(下)

文章目录 G1ShenandoahZGC 常见垃圾回收期&#xff08;上&#xff09; G1 参数1&#xff1a; -XX:UseG1GC 打开G1的开关&#xff0c;JDK9之后默认不需要打开 参数2&#xff1a;-XX:MaxGCPauseMillis毫秒值 最大暂停的时间 回收年代和算法 ● 年轻代老年代 ● 复制算法 优点…

Methoxy PEG Propionic acid具有良好的亲水性和分子量可控性

【试剂详情】 英文名称 mPEG-PA&#xff0c;mPEG-Propionic acid&#xff0c; Methoxy PEG PA&#xff0c; Methoxy PEG Propionic acid 中文名称 聚乙二醇单甲醚丙酸&#xff0c; 甲氧基-聚乙二醇-丙酸 外观性状 由分子量决定&#xff0c;固体或者液体 分子量 400&…