C++——异常

前言:本篇文章我们来分享C++的一个全新内容——异常。


目录

一.异常概念

二.异常的使用

 1.异常的抛出和匹配原则 

2.在函数调用链中异常栈展开匹配原则

3.异常的重新抛出

三.异常的优缺点

1.优点

2.缺点

结语


一.异常概念

异常是一种处理错误的方式,当一个函数发现自己无法处理的错误时就可以抛出异常,让函数的直接或间接的调用者处理这个错误

异常的使用包含以下三个关键字:

  • throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。
  • catch: 在您想要处理问题的地方,通过异常处理程序捕获异常.catch 关键字用于捕获异常,可以有多个catch进行捕获。
  • try: try 块中的代码标识将被激活的特定异常,它后面通常跟着一个或多个 catch 块。

如果有一个块抛出一个异常,捕获异常的方法会使用 try 和 catch 关键字。try 块中放置可能抛出异常的代码,try 块中的代码被称为保护代码。使用 try/catch 语句的语法如下所示:

try
{
  // 保护的标识代码
}catch( ExceptionName e1 )
{
  // catch 块
}catch( ExceptionName e2 )
{
  // catch 块
}catch( ExceptionName eN )
{
  // catch 块

简单来说,就是try区域保护某些语句,当语句出现异常时,由throw抛出一个某种类型的异常对象,通过与多个catch语句的对象类型进行匹配,再执行catch中的语句。 


二.异常的使用

 1.异常的抛出和匹配原则 

  1. 异常是通过抛出对象而引发的,该对象的类型决定了应该激活哪个catch的处理代码
  2. 被选中的处理代码是调用链中与该对象类型匹配且离抛出异常位置最近的那一个。
  3.  抛出异常对象后,会生成一个异常对象的拷贝,因为抛出的异常对象可能是一个临时对象,所以会生成一个拷贝对象,这个拷贝的临时对象会在被catch以后销毁。(这里的处理类似于函数的传值返回)
  4. catch(...)可以捕获任意类型的异常,问题是不知道异常错误是什么。
  5. 实际中抛出和捕获的匹配原则有个例外,并不都是类型完全匹配,可以抛出的派生类对象使用基类捕获

2.在函数调用链中异常栈展开匹配原则

  1. 首先检查throw本身是否在try块内部,如果是再查找匹配的catch语句。如果有匹配的,则调到catch的地方进行处理。
  2. 没有匹配的catch则退出当前函数栈,继续在调用函数的栈中进行查找匹配的catch。
  3. 如果到达main函数的栈,依旧没有匹配的,则终止程序。上述这个沿着调用链查找匹配的catch子句的过程称为栈展开。所以实际中我们最后都要加一个catch(...)捕获任意类型的异常,否则当有异常没捕获,程序就会直接终止。
  4. 找到匹配的catch子句并处理以后,会继续沿着catch子句后面继续执行。

下面我们实战一下异常的使用:

void Func()
{int a, b;cin >> a >> b;// 当b == 0时抛出异常if (b == 0)throw "Division by zero condition!";else if (a == 0)throw 1;elsecout << "no error" << endl;
}
int main()
{try {Func();}catch (const char* errmsg){cout << errmsg << endl;}catch (...) {cout << "unkown exception" << endl;}return 0;
}

可以看出,Func函数是我们要保护的语句当b == 0时,我们认为出现异常,此时通过throw抛出一段字符串,当a == 0时,也认为出现异常,通过throw抛出1,catch进行字符串类型的匹配,以及对未知类型的匹配,三种结果如下:

无异常:

有异常匹配字符串类型:

有异常匹配未知类型:


3.异常的重新抛出

有的时候,异常的抛出并不一定处于合理的位置,来看下面代码:

void Func()
{int a, b;cin >> a >> b;int* array = new int[10];// 当b == 0时抛出异常if (b == 0)throw "Division by zero condition!";else if (a == 0)throw 1;elsecout << "no error" << endl;cout << "delete []" << array << endl;delete[] array;
}

这里我们new了一个数组,但是在函数中,如果抛出了异常,函数是不会继续往下执行语句的,这样就到账我们的数组无法被释放。

所以说这里我们捕获异常之后,并不去处理它,而是将其重新抛出去,具体操作为:

void Func()
{int a, b;cin >> a >> b;int* array = new int[10];try{// 当b == 0时抛出异常if (b == 0)throw "Division by zero condition!";else if (a == 0)throw 1;elsecout << "no error" << endl;}catch(...){cout << "delete []" << array << endl;delete[] array;throw;}cout << "delete []" << array << endl;delete[] array;
}

三.异常的优缺点

1.优点

  1. 异常对象定义好了,相比错误码的方式可以清晰准确的展示出错误的各种信息,甚至可以包
    含堆栈调用的信息,这样可以帮助更好的定位程序的bug。
  2. 很多的第三方库都包含异常,比如boost、gtest、gmock等等常用的库,那么我们使用它们
    也需要使用异常。
  3.  部分函数使用异常更好处理,比如构造函数没有返回值,不方便使用错误码方式处理。比如
    T& operator这样的函数,如果pos越界了只能使用异常或者终止程序处理,没办法通过返回值表示错误。

2.缺点

  1. 异常会导致程序的执行流乱跳,并且非常的混乱,并且是运行时出错抛异常就会乱跳。这会
    导致我们跟踪调试时以及分析程序时,比较困难。
  2. 异常会有一些性能的开销。当然在现代硬件速度很快的情况下,这个影响基本忽略不计。
  3.  C++没有垃圾回收机制,资源需要自己管理。有了异常非常容易导致内存泄漏、死锁等异常
    安全问题。这个需要使用RAII来处理资源的管理问题。学习成本较高。
  4.  C++标准库的异常体系定义得不好,导致大家各自定义各自的异常体系,非常的混乱。
  5. 异常尽量规范使用,否则后果不堪设想,随意抛异常,外层捕获的用户苦不堪言。所以异常
    规范有两点:一、抛出异常类型都继承自一个基类。二、函数是否抛异常、抛什么异常,都使用 func() throw();的方式规范化。

总体而言,异常的利大于弊,所以在实践中还是非常支持去使用异常的。 


结语

关于异常就分享这么多,喜欢本篇文章记得一键三连,我们下期再见!

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

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

相关文章

完成QT上位机(八)

一. 正式开始设计界面 这一章节我们将完成QT上位机的设计&#xff0c;如果有同学对QtCreater的使用不太熟悉的&#xff0c;可以参考下面的链接 Qt 快速入门系列教程 Qt 快速入门系列教程 (gitbooks.io)https://wizardforcel.gitbooks.io/qt-beginning/content/ 二. 数据库处…

自动气象站:高度自动化、智能化和精准化

自动气象站&#xff0c;作为科技进步的产物&#xff0c;以其高度的自动化、智能化和精准化特点&#xff0c;极大地提升了气象观测的效率和准确性。它集成了多种高精度传感器&#xff0c;能够全天候、不间断地监测温度、湿度、气压、风速、风向、降水量等关键气象要素&#xff0…

小试牛刀-Telebot区块链游戏机器人(TS升级)

目录 1.编写目的 2.为什么使用TypeScript实现? 3.实现功能 3.1 AI图片生成 3.2 签到 3.3 邀请 3.4 WalletConnect连接 4.功能实现详解 4.1 AI图片生成 4.2 签到 4.3 邀请 4.4 WalletConnect连接 5.功能截图 ​6.问题整理 Welcome to Code Blocks blog 本篇文章主…

【图解秒杀系列】秒杀场景介绍及其相关技术点

【图解秒杀系列】秒杀场景介绍及其相关技术点 秒杀场景介绍秒杀页面的交互秒杀的整套流程 秒杀系统面临的挑战秒杀涉及的技术点 秒杀场景介绍 电商系统的秒杀是一种营销活动&#xff0c;在特定的时间点&#xff0c;以极低的价格&#xff0c;有限的商品数量&#xff0c;吸引大量…

【JavaEE初阶】懒汉模式与饿汉模式及指令重排序问题

目录 &#x1f4d5; 单例模式 &#x1f333; 饿汉模式 &#x1f6a9; 线程安全 &#x1f38d; 懒汉模式 &#x1f6a9; 懒汉模式-单线程版 &#x1f6a9; 懒汉模式-多线程版 &#x1f384; 指令重排序 &#x1f4d5; 单例模式 单例模式是一种经典的设计模式&#xff0c;…

node.js使用NodeMachineID 生成唯一UUID和注意事项

node-machine-id用于获取或生成唯一的机器ID 如何使用 const { machineId, machineIdSync } require(node-machine-id) JSON.stringify(machineIdSync({original: true})) ;方法&#xff1a; machineIdSync 此函数同步获取操作系统本机UUID/GUID&#xff0c;默认情况下进行哈…

视频教程 - 自研Vue3 Tree组件高级功能:虚拟滚动新增节点实现自动滚动

感谢小伙伴们对本套自研vue3 tree组件教程的关注&#xff0c;在前一篇媲美Element Plus JuanTree终极实战&#xff1a;虚拟滚动的功能演示中发现了小bug&#xff0c;特地整理了相关录屏来说明怎么一步步解决bug的&#xff0c;来回馈小伙伴们的支持。 Tree组件高级功能&#xff…

redis面试(四)持久化

什么是持久化&#xff1f; 由于redis是基于内存操作的轻量型数据库&#xff0c;所以如果发生宕机重启这种事情&#xff0c;存储的数据就会直接丢失&#xff0c;如果在里面存储了没有备份的数据&#xff0c;那么确实会对我们的业务造成一定影响。 所以我们要通过持久化的手段&a…

C# OpenCvSharp 打开4K高清摄像头

一、前言 整了个1200w像素的usb摄像头&#xff0c;使用 OpenCvSharp读取&#xff0c;读取和设置分辨率代码耗时居然10几秒&#xff0c;查询资料发现&#xff0c;必须对VideoCapture进行设置&#xff0c;使用DSHOW模式打开&#xff0c;并且设置分辨率代码下必须增加 指定MJPG编码…

pip‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。

重新设置一下环境变量。 注意&#xff0c;这里后面没有斜杠 我之前就是因为环境变量中&#xff0c;这两行最后都有斜杠&#xff0c;导致提示pip‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。

红旗E-QM5起火,一汽红旗否认车辆质量问题

近日&#xff0c;据媒体报道&#xff0c;7月31日下午&#xff0c;长春一辆一汽红旗E-QM5发生起火事故。 一汽红旗方面则表示&#xff1a;“现场勘查和初步调查表明&#xff0c;该事件并非因车辆自身质量问题导致自燃。疑似车辆在行驶过程中与路面井盖发生碰撞导致动力电池受损&…

计算机网络-基于PIM-DM+IGMP的组播实验配置

前面我们将IGMP协议和PIM-DM协议理论知识都学完了&#xff0c;现在开始进入实践&#xff0c;毕竟只有完成实践是最好的检验方式。IGMP是用于感知组播组成员&#xff0c;而PIM-DM是用于在域内构建组播分发树的的协议&#xff0c;本次实验使用这两项技术进行分析与实践。 一、拓扑…

upload-labs漏洞靶场~文件上传漏洞

寻找测试网站的文件上传的模块&#xff0c;常见&#xff1a;头像上传&#xff0c;修改上传&#xff0c;文件编辑器中文件上传&#xff0c;图片上传、媒体上传等&#xff0c;通过抓包上传恶意的文件进行测试&#xff0c;上传后缀名 asp php aspx 等的动态语言脚本&#xff0c;查…

电脑新加的硬盘如何分区?新加硬盘分区选MBR还是GPT

最近有网友问我,电脑新加的硬盘如何分区?电脑新加的硬盘分区选MBR还是GPT要看引导模式采用uefi还是传统的legacy模式&#xff0c;如果采用的是uefi引导模式&#xff0c;分区类型对应的就是gpt分区(guid)&#xff0c;如果引导模式采用的是legacy&#xff0c;对应的分区类型为mb…

Spring Boot集成sse实现chatgpt流式交互

​ 博客主页: 南来_北往 系列专栏&#xff1a;Spring Boot实战 什么是sse&#xff1f; SSE可以指代两种不同的概念&#xff1a;一是指“服务器发送事件”(Server-Sent Events)&#xff0c;另一种是指英特尔的“因特网数据流单指令序列扩展”(Streaming SIMD Extensions)。…

循环结构(三)——do-while语句

目录 &#x1f341;引言 &#x1f341;一、语句格式 &#x1f680;格式1 &#x1f680;格式2 &#x1f341;二、语句执行过程 &#x1f341;三、实例 &#x1f680;【例1】 &#x1f680;【例2】 &#x1f680;【例3】 &#x1f341;总结 &#x1f341;备注 &am…

Unity获取Animator动画播放完成事件

整理了一些在日常经验中处理动画播放完成事件的方法 方法: 1.Dotween配合异步实现 2.状态机计时方法实现 3.原生动画行为方法实现 方法一&#xff1a;Dotween异步方法 using UnityEngine; using System.Threading.Tasks; using DG.Tweening;public class PlayerAnimAsync : M…

Java——多线程(6/9):线程池、处理Runnable、Callable任务(认识线程池-线程池的工作原理,ThreadPoolExecutor构造器)

目录 认识线程池 介绍 线程池的工作原理 如何创建线程池 介绍 ThreadPoolExecutor构造器 代码实例 线程池的注意事项 线程池处理Runnable任务 ExecutorService的常用方法 代码实例 新任务拒绝策略 线程池处理Callable任务 ExecutorService的常用方法 代码实例…

如何从智联招聘网站快速抓取职位详情?两大技巧揭秘

摘要&#xff1a; 本文将揭秘如何利用Python爬虫技术&#xff0c;高效且合法地从智联招聘网站抓取职位详情信息。通过实战示例&#xff0c;展现两大核心技巧&#xff0c;助你在大数据时代抢占先机&#xff0c;为你的市场分析、人才研究提供强大支持。 一、引言&#xff1a;数据…

排序算法:冒泡排序,golang实现

目录 前言 冒泡排序 代码示例 1. 算法包 2. 冒泡排序代码 3. 模拟排序 4. 运行程序 5. 从大到小排序 循环细节 外层循环 内层循环 总结 循环次数测试 假如 10 条数据进行排序 假如 20 条数据进行排序 假如 30 条数据进行排序 假设 5000 条数据&#xff0c;对比…