当前位置: 首页 > news >正文

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++ 提供了一系列标准的异常,定义在 中,这些异常是我们程序中容易犯错的结果,我们可以在程序中使用这些标准的异常,异常家族👪👪👪结构图如下(一部分):

在这里插入图片描述

下表是对上面层次结构中出现的每个异常的说明:

异常描述
std::exception该异常是所有标准 C++ 异常的父类
std::bad_alloc该异常可以通过 new 抛出。
std::bad_cast该异常可以通过 dynamic_cast 抛出。
std::bad_exception这在处理 C++ 程序中无法预期的异常时非常有用。
std::bad_typeid该异常可以通过 typeid 抛出。
std::logic_error理论上可以通过读取代码来检测到的异常。
std::domain_error当使用了一个无效的数学域时,会抛出该异常。
std::invalid_argument当使用了无效的参数时,会抛出该异常。
std::length_error当创建了太长的 std::string 时,会抛出该异常。
std::out_of_range该异常可以通过方法抛出,例如 std::vector 和 std::bitset<>::operator
std::runtime_error用于表示那些在程序运行时可能发生的错误.
std::overflow_error当发生数学上溢时,会抛出该异常。
std::range_error当尝试存储超出范围的值时,会抛出该异常。
std::underflow_error当发生数学下溢时,会抛出该异常。

结合我们之前学过的面向对象,封装、继承、多态,我们可以发现,这些异常都是继承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那样,动不动就抛一个异常,以下是使用异常的一些标准

    1. 如果程序是逻辑错误,则不应该抛出异常,应该解决他

    2. 如果后面的代码,依赖这个结果,那么这个有异常情况,则可以抛出异常

    3. 如果后面的代码不依赖这个结果,则不应该抛出异常

    4. 异常不能用if……else代替

相关文章:

C/C++语言基础--C++异常看这一篇就够了

本专栏目的 更新C/C的基础语法&#xff0c;包括C的一些新特性 前言 通过前面几节课&#xff0c;我们学习了抽象、封装、继承、多态等相关的概念&#xff0c;接下来我们将讲解异常&#xff0c;异常是专门处理错误的&#xff1b;这一次加了不少图标&#xff0c;希望大家喜欢;C语…...

DFT ATPG中常见影响coverage的因素有哪些?

# DFT ATPG中常见影响Coverage的因素 ## 一、电路结构复杂性 1. **逻辑层次深度** - **原理** - 当电路的逻辑层次很深时,信号在传播过程中会经过多个逻辑门的处理。这使得测试向量难以准确地控制和观察内部节点的状态。例如,在一个具有多层嵌套逻辑的电路中,如一个…...

Python机器学习数据清洗到特征工程策略

Python机器学习数据清洗到特征工程策略 目录 ✨ 数据清洗&#xff1a;处理缺失值与异常值的策略&#x1f504; 特征选择&#xff1a;筛选与数据目标高度相关的特征&#x1f6e0; 特征工程&#xff1a;数据转换与生成新特征的多样化方法&#x1f4ca; 类别型变量的数值化&…...

多线程-进阶(2)CountDownLatchConcurrentHashMapSemaphore

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

密码管理器KeePass的安装及使用

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

星海智算:【萤火遛AI-Stable-Diffusion】无需部署一键启动

部署流程 1、注册算力云平台&#xff1a;星海智算 https://gpu.spacehpc.com/ 2、创建实例&#xff0c;镜像请依次点击&#xff1a;“镜像市场”->“更换”->“AI绘画”->“萤火遛AI-Stable Diffusion”。 程序首次启动可能需要几分钟&#xff0c;待实例显示“运行…...

JS生成器的特殊用法:委托yield*

yield 的基本用法 yield 用于在生成器函数中暂停函数执行&#xff0c;并返回一个值给外部调用者。当生成器再次被调用时&#xff0c;会从暂停的地方继续执行。 示例&#xff1a; function* simpleGenerator() {yield 1;yield 2;yield 3; }const gen simpleGenerator();cons…...

【CuPy报错】NVRTC_ERROR_COMPILATION (6)找不到 ‘vector_types.h‘

cupy安装不要再使用pip install cupy了&#xff0c; 已经替换成基于版本安装了pip install cupy-cuda12x&#xff0c;详见cupy官网。 安装完成后&#xff0c;在import cupy之后报错&#xff0c;找不到 ‘vector_types.h’: CompileException: /home/zoe/venv/lib/python3.10/…...

机器学习:知识蒸馏(Knowledge Distillation,KD)

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

【C++入门篇 - 3】:从C到C++第二篇

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

YOLOv8模型改进 第七讲 一种新颖的注意力机制 Outlook Attention

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

C#多线程基本使用和探讨

线程是并发编程的基础概念之一。在现代应用程序中&#xff0c;我们通常需要执行多个任务并行处理&#xff0c;以提高性能。C# 提供了多种并发编程工具&#xff0c;如Thread、Task、异步编程和Parallel等。 Thread 类 Thread 类是最基本的线程实现方法。使用Thread类&#xff0…...

PHP DateTime基础用法

PHP DateTime 的用法详解 一、引言 在开发 PHP 应用程序时&#xff0c;处理日期和时间是一个至关重要的任务。PHP 提供了强大的日期和时间处理功能&#xff0c;其中 DateTime 类是最常用的工具之一。DateTime 类提供了丰富的方法来创建、格式化、计算和比较日期时间&#xff…...

一次Fegin CPU占用过高导致的事故

记录一下 一次应用事故分析、排查、处理 背景介绍 9号上午收到CPU告警&#xff0c;同时业务反馈依赖该服务的上游服务接口响应耗时太长 应用告警-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定义了包名。你必须在源文件中非注释的第一行指明这个文件属于哪个包&#xff0c;如&#xff1a;package main…...

【React】使用 react hooks 需要遵守的原则

1&#xff09;只能在顶层调用Hooks 这是指你不能在循环、条件语句或嵌套函数中调用Hooks。确保每次组件渲染时&#xff0c;Hooks的调用顺序保持一致。因此&#xff0c;你应该始终在React函数组件的最顶层调用Hooks。 React依赖于Hooks的调用顺序。如果这些调用在不同的渲染中顺…...

Python编程:创意爱心表白代码集

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

腾讯IM SDK:TUIKit发送多张图片

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

《本地部署开源大模型》在Ubuntu 22.04系统下ChatGLM3-6B高效微调实战

在Ubuntu 22.04系统下ChatGLM3-6B高效微调实战 无论是在单机单卡&#xff08;一台机器上只有一块GPU&#xff09;还是单机多卡&#xff08;一台机器上有多块GPU&#xff09;的硬件配置上启动ChatGLM3-6B模型&#xff0c;其前置环境配置和项目文件是相同的。如果大家对配置过程还…...

Python 脚本来自动发送每日电子邮件报告

安装必要的库 我们将使用 smtplib 发送邮件&#xff0c;以及 email.mime 来创建电子邮件内容。另外&#xff0c;为了让脚本自动定时运行&#xff0c;可以使用操作系统的计划任务工具&#xff08;如 Linux 的 cron 或 Windows 的 Task Scheduler&#xff09;。 创建邮件内容 使…...

Qwen3-14B镜像实操:自定义Tokenizer适配垂直领域专业术语

Qwen3-14B镜像实操&#xff1a;自定义Tokenizer适配垂直领域专业术语 1. 镜像概述与核心优势 Qwen3-14B私有部署镜像是专为RTX 4090D 24GB显存环境优化的完整解决方案&#xff0c;开箱即用无需复杂配置。这个镜像最显著的特点是针对垂直领域专业术语进行了Tokenizer的深度优化…...

Bypass Paywalls Clean:智能内容解锁工具的终极使用指南

Bypass Paywalls Clean&#xff1a;智能内容解锁工具的终极使用指南 【免费下载链接】bypass-paywalls-chrome-clean 项目地址: https://gitcode.com/GitHub_Trending/by/bypass-paywalls-chrome-clean 在数字化信息时代&#xff0c;学术研究者、新闻从业者和知识工作者…...

基于西门子PLC的空压机组储气风冷机组自动控制系统:“手动自动切换、多机控制及实时监测报警系统

基于西门子plc的空压机组储气风冷机组自动控制系统 可以实现手动自动切换 三组空压机分别自动控制&#xff0c;自动检测三路压力 风冷机运行实时检测 报警查寻&#xff0c;参数设置等上周刚把车间那套跑了快十年的空压机组控制系统给换了&#xff0c;用的是西门子S7-1200&#…...

抑制素A抗体如何提升妊娠中期唐氏综合征筛查的效能?

一、为何抑制素A成为妊娠期的重要生物标志物&#xff1f;抑制素A是一种由α和βA亚基通过二硫键连接形成的异源二聚体糖蛋白。在非妊娠期&#xff0c;它主要由卵巢颗粒细胞分泌&#xff0c;作为反馈调节因子&#xff0c;选择性地抑制垂体前叶分泌卵泡刺激素。进入妊娠状态后&am…...

PasteMD用户调研报告:2024年文档格式转换需求分析

PasteMD用户调研报告&#xff1a;2024年文档格式转换需求分析 1. 调研背景与核心发现 最近整理了500份来自不同行业用户的实际反馈&#xff0c;这些反馈不是问卷里的标准答案&#xff0c;而是真实工作场景中留下的痕迹——有深夜赶论文时的抱怨截图&#xff0c;有项目汇报前的…...

Real-ESRGAN-GUI:如何用AI双引擎将模糊图片一键变高清

Real-ESRGAN-GUI&#xff1a;如何用AI双引擎将模糊图片一键变高清 【免费下载链接】Real-ESRGAN-GUI Lovely Real-ESRGAN / Real-CUGAN GUI Wrapper 项目地址: https://gitcode.com/gh_mirrors/re/Real-ESRGAN-GUI 还在为模糊的老照片、低分辨率的动漫图片而烦恼吗&…...

豪鹏科技2025年财报透视:毛利率提升5.2个百分点,费用管控成效显著

豪鹏科技2025年财报透视&#xff1a;毛利率提升5.2个百分点&#xff0c;费用管控成效显著豪鹏科技2025年业绩表现亮眼&#xff0c;全年实现营业收入57亿元至60亿元&#xff0c;同比增长11.58%至17.45%&#xff1b;归母净利润1.95亿元至2.2亿元&#xff0c;同比大幅增长113.69%至…...

保姆级教程:在PX4 SITL仿真中为Iris无人机挂载Kinect、RPLidar和FPV摄像头

PX4仿真环境多传感器集成实战&#xff1a;从零搭建SLAM无人机开发平台 无人机仿真开发中最令人头疼的&#xff0c;莫过于将各类传感器完美集成到飞行平台上。我曾花了整整两周时间调试Kinect和RPLidar在Gazebo中的兼容性问题&#xff0c;直到找到这套经过验证的解决方案。本文将…...

UI设计入门指南——Figma新手必备操作全解析

1. Figma入门&#xff1a;从零到第一个设计稿 第一次打开Figma时&#xff0c;很多人会被满屏的英文界面和复杂工具栏吓到。其实我刚接触时也一样&#xff0c;但现在回头看&#xff0c;掌握基础操作只需要30分钟。Figma作为目前最流行的UI设计工具&#xff0c;最大的优势就是零门…...

Bambu Studio 3D打印切片实战指南:从技术原理到场景应用

Bambu Studio 3D打印切片实战指南&#xff1a;从技术原理到场景应用 【免费下载链接】BambuStudio PC Software for BambuLab and other 3D printers 项目地址: https://gitcode.com/GitHub_Trending/ba/BambuStudio Bambu Studio作为一款专为3D打印优化的开源切片软件&…...