C/C++语言基础--C++异常看这一篇就够了
本专栏目的
- 更新C/C++的基础语法,包括C++的一些新特性
前言
- 通过前面几节课,我们学习了抽象、封装、继承、多态等相关的概念,接下来我们将讲解异常,异常是专门处理错误的;
- 这一次加了不少图标,希望大家喜欢;
- C语言后面也会继续更新知识点,如内联汇编;
- 欢迎收藏 + 关注,本人将会持续更新。
文章目录
- :eyes: 先看问题
- :question: 什么是异常?
- :arrow_upper_right: 抛出异常
- :cat: 捕获异常
- :star: C++ 标准的异常
- :new: 定义新的异常(有头文件)
- :accept: 万能接收异常
- :stop_button: 抑制new抛异常
- :see_no_evil: 函数中捕获异常注意点
- :atom_symbol: 异常注意点:
👀 先看问题
我们先来看这一段代码:
void _div(double a, double b)
{std::cout << a / b << std::endl;
}
这段代码很简单,就是实现一个除法运算,但是这个代码有一个很大的bug🍴🍴🍴,就是没有判断b!=0
的情况,所以很多人写代码的时候是这样写的:
void _div(double a, double b)
{if(b == 0) {std::cout << "除数不能为0" << std::endl;return;}std::cout << a / b << std::endl;
}
🚫 🚫🚫 但是如果我们忘记了写判断,而这一段代码在一个程序中无非就是一个小部分,如果我们忘记写这个判断了,程序就会引发中断,而这个是逻辑错误,不是代码错误,编译器是不会提示的,所以这个时候我们就需要一个一个去找bug的位置了🐛🐛🐛🐛🐛🐛,那有什么更好的解决方法呢?
当然有💪,这就是异常。
❓ 什么是异常?
异常是程序在执行期间产生的问题,也就是指在程序运行时发生的特殊情况,比如我们上面的尝试除以零的操作。
为什么异常可以这样解决程序中产生的问题呢?
概念:异常处理提供了一种可以使程序从执行的某点将控制流和信息转移到与执行先前经过的某点相关联的处理代码的方法,换言之,异常处理就是将控制权沿调用栈向上转移。
🔑 关键:
- 将程序运行的的PC指针沿着栈向上移动
- 换句话说:就是将程序出现异常的时候那个位置移动到另外一个位置。
4️⃣ C++处理异常API
C++ 异常处理涉及到四个关键字:**try、catch、throw、noexcept **。
-
throw::程序会抛出一个异常。
-
catch: 通过异常处理程序捕获异常。
-
try: try中存放是否需要检查有异常的的代码段,它后面通常跟着一个或多个 catch 块。
-
try {// 保护代码 }catch( ExceptionName e1 ) // ExceptionName 异常类型名字 {// catch 块 }catch( ExceptionName e2 ) {// catch 块 }catch( ExceptionName eN ) {// catch 块 }
-
-
**noexcept :**用于描述函数不会抛出异常,一旦有异常抛出,会立刻终止程序,它可以阻止异常的传播与扩散;
- 扩展:noexcept可以带一个“常量表达式作为参数,常量表达式为true,表示不会抛出异常,否则代表可以抛出异常,如:noexpect(true) (也是默认的),noexpect(false)
int show() noexpect // 声明这个函数不会抛出异常 {throw 0; }int show() noexpect(false) // 声明这个函数*** 会 *** 抛出异常 {throw 0; }
↗️ 抛出异常
我们上面可以知道,跑出异常的关键字是throw,那具体怎么使用呢?我们这里以解决我们上面的案例为例❗️❗️
double _div(double a, double b)
{if( b == 0 ) // 除数为0,错误,抛出异常{throw "Division by zero condition!"; }return (a / b);
}
🐱 捕获异常
catch 块跟在 try 块后面,用于捕获异常。我们可以指定想要捕捉的异常类型,通过指定 catch 关键字即可。
double _div(double a, double b)
{try{if (b == 0) // 除数为0,错误,抛出异常{throw std::runtime_error("Division by zero condition!");}return (a / b);}catch (std::exception& err) {std::cout << err.what() << std::endl;}
}
上面的代码会捕获一个类型为 std::runtime_error的异常,catch
存放处理异常方法,这样就不会发送中断了,运如图:
抛出异常代码模板结构大概如下:
try
{// 保护代码
}catch(...)
{// 能处理任何异常的代码
}
当然,catch还可以多个,多次匹配不同的问题:,如下代码🕶🕶🕶
double _div(double a, double b)
{try{if (b == 0) // 除数为0,错误,抛出异常{throw 0;}return (a / b);}catch (const char* err) {std::cout << err << std::endl;}catch (int& err) {std::cout << 1 << std::endl;}
}
运行结果:
由于我们抛出了一个类型为 int 的异常,在捕获异常的时候,他会匹配不同抛出异常的类型,我们抛出的是整形
所以C++会自动寻找相对应位置。
❓ 如果throw的类型,在catch中没有找到会怎么样子呢?这个就留给读者思考吧🤔🤔🤔🤔
⭐️ C++ 标准的异常
C++ 提供了一系列标准的异常,定义在 中,这些异常是我们程序中容易犯错的结果,我们可以在程序中使用这些标准的异常,异常家族👪👪👪结构图如下(一部分):
下表是对上面层次结构中出现的每个异常的说明:
结合我们之前学过的面向对象,封装、继承、多态,我们可以发现,这些异常都是继承exception类,所以,对于这些标准异常的捕获处理,我们就可以得到如下代码结构:
try {throw 标准库中含有的异常;
}
catch(std::exception& err){}
🆕 定义新的异常(有头文件)
您可以通过继承和重载 exception 类来定义新的异常。下面的实例演示了如何使用 std::exception 类来实现自己的异常:
#include <iostream>
#include <exception>
using namespace std;struct MyException : public exception //exception 在std命名空间里面
{const char * what () const{return "C++ Exception";}
};int main()
{try{throw MyException();}catch(MyException& e){std::cout << "MyException caught" << std::endl;std::cout << e.what() << std::endl;}catch(std::exception& e){//其他的错误}
}
这将产生以下结果:
MyException caught
C++ Exception
🉑 万能接收异常
C++考虑的很全面,提供了一个能够捕获万能捕获异常的方法,...
,代码结构如下:
try {throw "hello";
} catch (...) {}
我们将案例用这个方法捕获:
double _div(double a, double b)
{try{if (b == 0) // 除数为0,错误,抛出异常{throw 0;}return (a / b);}catch (...) {std::cout << __FUNCTION__ << " 代码有问题" << std::endl;}
}
结果:
⏹ 抑制new抛异常
当使用new申请内存时,如果内存申请失败,会抛出std::bad_alloc异常,如果像让他不发生异常则需要如下处理(学习github某一位老师的笔记)。
- 测试的时候,需要换成 x86 环境下(2g),x64 理论上无限内存
try
{while (true){new char[1024];}
}
catch (const std::bad_alloc& e)
{cout << "has exception "<<e.what() << endl;
}
如果想根据返回的指针来判断,就需要抑制new抛出异常。
double* p = nullptr;
do
{p = new(std::nothrow) double[1024]; //声明让 new 不抛出异常
} while (p);
🙈 函数中捕获异常注意点
当在函数中没有匹配处理该抛出异常的操作,这个时候会他会到函数调用的地方去寻找匹配,如下:
double _div(double a, double b)
{try{if (b == 0) // 除数为0,错误,抛出异常, *** 但是没有匹配 0 的代码 ***{throw 0;}return (a / b);}catch (const char* msg) { // 匹配字符串类型的std::cout << __FUNCTION__ << " 代码有问题" << std::endl;}
}// 这个时候回到函数调用的地方找寻
int main()
{try {_div(10, 0);}catch (...) { // 这个地方找std::cout << "main" << std::endl;}}
运行结果图如下:
⚛️ 异常注意点:
-
类的构造函数不抛出异常
-
异常不能乱用,C++一般用的不多,不像java那样,动不动就抛一个异常,以下是使用异常的一些标准
-
如果程序是逻辑错误,则不应该抛出异常,应该解决他
-
如果后面的代码,依赖这个结果,那么这个有异常情况,则可以抛出异常
-
如果后面的代码不依赖这个结果,则不应该抛出异常
-
异常不能用if……else代替
-
相关文章:

C/C++语言基础--C++异常看这一篇就够了
本专栏目的 更新C/C的基础语法,包括C的一些新特性 前言 通过前面几节课,我们学习了抽象、封装、继承、多态等相关的概念,接下来我们将讲解异常,异常是专门处理错误的;这一次加了不少图标,希望大家喜欢;C语…...
DFT ATPG中常见影响coverage的因素有哪些?
# DFT ATPG中常见影响Coverage的因素 ## 一、电路结构复杂性 1. **逻辑层次深度** - **原理** - 当电路的逻辑层次很深时,信号在传播过程中会经过多个逻辑门的处理。这使得测试向量难以准确地控制和观察内部节点的状态。例如,在一个具有多层嵌套逻辑的电路中,如一个…...
Python机器学习数据清洗到特征工程策略
Python机器学习数据清洗到特征工程策略 目录 ✨ 数据清洗:处理缺失值与异常值的策略🔄 特征选择:筛选与数据目标高度相关的特征🛠 特征工程:数据转换与生成新特征的多样化方法📊 类别型变量的数值化&…...

多线程-进阶(2)CountDownLatchConcurrentHashMapSemaphore
目的; JUC(java.util.concurrent) 的常⻅类 接着上一节课到 1.信号量 Semaphore 信号量, ⽤来表⽰ "可⽤资源的个数". 本质上就是⼀个计数器。 理解信号量 可以把信号量想象成是停⻋场的展⽰牌: 当前有⻋位 100 个. 表⽰有 100 个可⽤资源. 当有⻋开进去的时候,…...

密码管理器KeePass的安装及使用
文章目录 软件下载安装汉化新建数据库创建\移动\修改 群组添加/修改/删除/移动 记录展示、搜索、锁定单独使用keepass生成密码的功能AES-256的密钥长度为256位,为啥可以设置超过32个字符的密钥? 软件下载 安装 分别解压:KeePass-2.53.1.zip&…...

星海智算:【萤火遛AI-Stable-Diffusion】无需部署一键启动
部署流程 1、注册算力云平台:星海智算 https://gpu.spacehpc.com/ 2、创建实例,镜像请依次点击:“镜像市场”->“更换”->“AI绘画”->“萤火遛AI-Stable Diffusion”。 程序首次启动可能需要几分钟,待实例显示“运行…...
JS生成器的特殊用法:委托yield*
yield 的基本用法 yield 用于在生成器函数中暂停函数执行,并返回一个值给外部调用者。当生成器再次被调用时,会从暂停的地方继续执行。 示例: function* simpleGenerator() {yield 1;yield 2;yield 3; }const gen simpleGenerator();cons…...
【CuPy报错】NVRTC_ERROR_COMPILATION (6)找不到 ‘vector_types.h‘
cupy安装不要再使用pip install cupy了, 已经替换成基于版本安装了pip install cupy-cuda12x,详见cupy官网。 安装完成后,在import cupy之后报错,找不到 ‘vector_types.h’: CompileException: /home/zoe/venv/lib/python3.10/…...

机器学习:知识蒸馏(Knowledge Distillation,KD)
知识蒸馏(Knowledge Distillation,KD)作为深度学习领域中的一种模型压缩技术,主要用于将大规模、复杂的神经网络模型(即教师模型)压缩为较小的、轻量化的模型(即学生模型)。在实际应…...

【C++入门篇 - 3】:从C到C++第二篇
文章目录 从C到C第二篇new和delete命名空间命名空间的访问 cin和coutstring的基本使用 从C到C第二篇 new和delete 在C中用来向系统申请堆区的内存空间 New的作用相当于C语言中的malloc Delete的作用相当于C语言中的free 注意:在C语言中,如果内存不够…...

YOLOv8模型改进 第七讲 一种新颖的注意力机制 Outlook Attention
随着目标检测技术的不断发展,YOLOv8 作为最新一代的目标检测模型,已经在多个基准数据集上展现了其卓越的性能。然而,在复杂场景中,如何进一步提升模型的检测精度和鲁棒性依然是一个重要挑战。本文将探讨将 Outlook Attention 机制…...

C#多线程基本使用和探讨
线程是并发编程的基础概念之一。在现代应用程序中,我们通常需要执行多个任务并行处理,以提高性能。C# 提供了多种并发编程工具,如Thread、Task、异步编程和Parallel等。 Thread 类 Thread 类是最基本的线程实现方法。使用Thread类࿰…...
PHP DateTime基础用法
PHP DateTime 的用法详解 一、引言 在开发 PHP 应用程序时,处理日期和时间是一个至关重要的任务。PHP 提供了强大的日期和时间处理功能,其中 DateTime 类是最常用的工具之一。DateTime 类提供了丰富的方法来创建、格式化、计算和比较日期时间ÿ…...

一次Fegin CPU占用过高导致的事故
记录一下 一次应用事故分析、排查、处理 背景介绍 9号上午收到CPU告警,同时业务反馈依赖该服务的上游服务接口响应耗时太长 应用告警-CPU使用率 告警变更 【WARNING】项目XXX,集群qd-aliyun,分区bbbb-prod,应用customer,实例customer-6fb6448688-m47jz, POD实例CP…...

【Go初阶】两万字快速入门Go语言
初见golang语法 package mainimport "fmt"func main() {/* 简单的程序 万能的hello world */fmt.Println("Hello Go")} 第一行代码package main定义了包名。你必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main…...
【React】使用 react hooks 需要遵守的原则
1)只能在顶层调用Hooks 这是指你不能在循环、条件语句或嵌套函数中调用Hooks。确保每次组件渲染时,Hooks的调用顺序保持一致。因此,你应该始终在React函数组件的最顶层调用Hooks。 React依赖于Hooks的调用顺序。如果这些调用在不同的渲染中顺…...

Python编程:创意爱心表白代码集
在寻找一种特别的方式来表达你的爱意吗?使用Python编程,你可以创造出独一无二的爱心图案,为你的表白增添一份特别的浪漫。这里为你精选了六种不同风格的爱心表白代码,让你的创意和情感通过代码展现出来。 话不多说,咱…...

腾讯IM SDK:TUIKit发送多张图片
一、问题描述 在使用腾讯IM DEMO(https://github.com/TencentCloud/chat-uikit-vue.git)时发现其只支持发送一张图片: 二、解决方案 // src\TUIKit\components\TUIChat\message-input-toolbar\image-upload\index.vue<inputref"inp…...

《本地部署开源大模型》在Ubuntu 22.04系统下ChatGLM3-6B高效微调实战
在Ubuntu 22.04系统下ChatGLM3-6B高效微调实战 无论是在单机单卡(一台机器上只有一块GPU)还是单机多卡(一台机器上有多块GPU)的硬件配置上启动ChatGLM3-6B模型,其前置环境配置和项目文件是相同的。如果大家对配置过程还…...
Python 脚本来自动发送每日电子邮件报告
安装必要的库 我们将使用 smtplib 发送邮件,以及 email.mime 来创建电子邮件内容。另外,为了让脚本自动定时运行,可以使用操作系统的计划任务工具(如 Linux 的 cron 或 Windows 的 Task Scheduler)。 创建邮件内容 使…...

微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...

自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...

优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...
Spring Boot + MyBatis 集成支付宝支付流程
Spring Boot MyBatis 集成支付宝支付流程 核心流程 商户系统生成订单调用支付宝创建预支付订单用户跳转支付宝完成支付支付宝异步通知支付结果商户处理支付结果更新订单状态支付宝同步跳转回商户页面 代码实现示例(电脑网站支付) 1. 添加依赖 <!…...

Qt的学习(一)
1.什么是Qt Qt特指用来进行桌面应用开发(电脑上写的程序)涉及到的一套技术Qt无法开发网页前端,也不能开发移动应用。 客户端开发的重要任务:编写和用户交互的界面。一般来说和用户交互的界面,有两种典型风格&…...