【C++ 学习 ㉟】- 异常详解

news2024/10/6 22:23:23

目录

一、C++ 异常处理的基本语法

1.1 - 抛出异常

1.2 - 检测和捕获异常

二、在函数调用链中异常栈展开的匹配原则

三、异常重新抛出

四、异常规范

五、C++ 标准异常体系


程序的错误大致可以分为以下三种:

  1. 语法错误:在编译和链接阶段就能发现,只有符合语法规则的代码才能生成可执行程序。语法错误是最容易发现、最容易定位、最容易排除的错误,程序员最不需要担心的就是这种错误。

  2. 逻辑错误:编写的代码不能够达到预期的效果,这种错误可以通过调试来解决。

  3. 运行时错误:指程序在运行期间发生的错误,例如除数为 0、内存分配失败、数组下标越界、文件不存在等,如果不能发现这些错误并加以处理,很可能会导致程序崩溃。C++ 异常机制就是为了解决运行时错误而引入的


一、C++ 异常处理的基本语法

1.1 - 抛出异常

C++ 通过 throw 关键字抛出异常,语法为:

throw exceptionData;

exceptionData 可以是任意类型的异常数据

示例:

int division(int a, int b)
{
    if (b == 0)
        throw "Division by zero condition!";
    else
        return a / b;
}

1.2 - 检测和捕获异常

检测和捕获异常的语法为:

try {
    // 可能抛出异常的代码
}
catch (exceptionType1 e1) {
    // 处理异常的代码
}
...
catch (exceptionTypeN eN) {
    // 处理异常的代码
}

try...catch 语句的执行过程是:执行 try 块中的语句(称作检测异常),如果执行过程中没有异常抛出,那么所有 catch 块中的语句都不会被执行;如果执行过程中抛出了异常,那么抛出异常后会立即跳转到第一个异常类型和抛出的异常类型匹配的 catch 块,并执行其中的语句(称作捕获异常)

注意

  1. catch 可以有多个,但至少要有一个

  2. catch(...) 可以捕获任意类型的异常

  3. 可以使用基类捕获派生类对象

  4. 如果不希望处理异常数据,可以将 e1、...、eN 省略掉

示例:

#include <iostrea>
using namespace std;
​
class Base { };
class Derived : public Base { };
​
int main()
{
    try {
        throw Derived();
        cout << "This statement will not be executed." << endl;
    }
    catch (Base) {
        cout << "Exception type::Base" << endl;
    }
    catch (Derived) {
        cout << "Exception type::Derived" << endl;
    }
    catch (...) {
        cout << "Unknow exception" << endl;
    }
    // Exception type::Base
    return 0;
}


二、在函数调用链中异常栈展开的匹配原则

  1. 当异常被抛出后,首先检查 throw 语句是否在 try 块内部,如果在,则查找匹配的 catch 块

  2. 如果没找到匹配的 catch 块,则退出当前函数栈,继续在调用该函数的函数栈中查找匹配的 catch 块

  3. 如果到达 main 函数栈,依旧没有找到匹配的 catch 块,则终止程序

上述这个沿着函数调用链查找匹配的 catch 块的过程称为栈展开

#include <iostream>
using namespace std;
​
int division(int a, int b)
{
    if (b == 0)
        throw "Division by zero condition!";
    else
        return a / b;
}
​
void func()
{
    int a = 0, b = 0;
    cin >> a >> b;
    cout << division(a, b) << endl;
}
​
int main()
{
    try {
        func();
    }
    catch (const char* errmsg) {
        cout << errmsg << endl;
    }
    catch (...) {
        cout << "Unknow exception" << endl;
    }
    return 0;
}


三、异常重新抛出

单个 catch 块有可能不能完全处理一个异常,在进行一些校正处理后,希望将异常交给更外层的调用函数来处理,那么在 catch 块中就可以将异常重新抛出

#include <iostream>
using namespace std;
​
int division(int a, int b)
{
    if (b == 0)
        throw "Division by zero condition!";
    else
        return a / b;
}
​
void func()
{
    int* arr = new int[10];
    try {
        int a = 0, b = 0;
        cin >> a >> b;
        cout << division(a, b) << endl;
    }
    catch (...) {
        delete[] arr;
        cout << "func : delete[] finished" << endl;
        throw;  // 异常重新抛出
    }
    delete[] arr;
}
​
int main()
{
    try {
        func();
    }
    catch (const char* errmsg) {
        cout << errmsg << endl;
    }
    catch (...) {
        cout << "Unknow exception" << endl;
    }
    return 0;
}

throw; 没有指明抛出什么类型的异常,因此抛出的就是 catch 块捕获到的异常,这个异常会被 main 函数中的 catch 块捕获


四、异常规范

throw 关键字除了可以用在函数体中抛出异常,还可以用在函数头和函数体之间,指明当前函数能够抛出的异常类型,这称为异常规范

void func() throw(int);

这条语句声明了一个名为 func 函数,它的返回值类型为 void,参数列表为空,并且只能抛出 int 类型的异常,如果抛出其他类型的异常,try 将无法捕获,只能终止程序

如果函数会抛出多种类型的异常,那么可以用逗号隔开

void func() throw(int, char, double);

如果函数不会抛出任何任何异常,那么 () 中什么也不写

void func() throw();
// C++ 中新增的 noexcept 关键字,表示不会抛出异常
void func() noexcept;

此时,func() 函数就不能抛出任何类型的异常了,即使抛出了,try 也检测不到

·


五、C++ 标准异常体系

C++ 语言本身或者标准库中抛出的异常都是 exception 的子类,称为标准异常

exception 类位于 <exception> 头文件中,它被声明为:

class exception {
public:
    exception () throw();
    exception (const exception&) throw();
    exception& operator= (const exception&) throw();
    virtual ~exception() throw();
    virtual const char* what() const throw();
}

下图展示了 exception 类的继承层次:

实际上,很多公司都会自定义自己的异常体系进行规范的异常管理

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

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

相关文章

Linux——vim简介、配置方案(附带超美观的配置方案)、常用模式的基本操作

vim简介、配置方案、常用模式的基本操作 本章思维导图&#xff1a; 注&#xff1a;本章思维导图对应的xmind和.png文件都已同步导入至资源 1. vim简介 vim是Linux常用的文本编辑器&#xff0c;每个Linux账户都独有一个vim编辑器 本篇我们介绍vim最常用的三种模式&#xff1a;…

史上最全最新Ubuntu20.04安装教程(图文)

总的来说&#xff0c;安装Ubantu包含以下三个步骤&#xff1a; 一、安装虚拟机 二、Ubuntu镜像下载 三、虚拟机配置 一、安装虚拟机 选择安装VMware Workstation&#xff0c;登录其官网下载安装包&#xff0c;链接如下&#xff1a; 下载 VMware Workstation Pro​www.vmwa…

Linux中字符设备的打开、写入

一个内核模块应该由以下几部分组成。 第一部分&#xff0c;头文件部分。一般的内核模块&#xff0c;都需要 include 下面两个头文件&#xff1a; #include <linux/module.h> #include <linux/init.h> 第二部分&#xff0c;定义一些函数&#xff0c;用于处理内核…

【Python大数据笔记_day07_hive中的分区表、分桶表以及一些特殊类型】

分区表 分区表的特点/好处:需要产生分区目录,查询的时候使用分区字段筛选数据,避免全表扫描从而提升查询效率 效率上注意:如果分区表在查询的时候呀没有使用分区字段去筛选数据,效率不变 分区字段名注意:分区字段名不能和原有的字段名重复,因为分区字段名要作为字段拼接到表后…

常见面试题-JDK和CGLIB动态代理

JDK 动态代理和 CGLIB 动态代理对比 JDK 动态代理只能代理实现了接口的类&#xff0c;而 CGLIB 可以代理未实现任何接口的类。另外CGLIB 动态代理是通过生成一个被代理类的子类来拦截被代理类的方法调用&#xff0c;因此不能代理声明为final 类型的类和方法就二者的效率来说&a…

信息系统项目管理师 教材目录、考试大纲、考情

文章目录 考情考试大纲第1章 信息化发展第2章 信息技术发展第3章 信息系统治理第4章 信息系统管理第5章 信息系统工程第6章 项目管理概论第7章 项目立项管理第8章 项目整合管理第9章 项目范围管理272第10章 项目进度管理297第11章 项目成本管理334第12章 项目质量管理358第13章…

【图像卷积与卷积层】的基本概念与区别

图像卷积 卷积操作是指将一个滤波器&#xff08;也称为卷积核或内核&#xff09;应用于输入图像的小块区域&#xff0c;然后将滤波器在整个图像上滑动&#xff0c;逐步计算出输出特征图。这个过程可以帮助网络学习到图像的局部特征&#xff0c;因为每个卷积核都可以学习到不同…

VulnHub Prime_Series_Level-1

一、信息收集 1.nmap扫描 ┌──(root&#x1f480;kali)-[~/桌面] └─# arp-scan -l┌──(root&#x1f480;kali)-[~/桌面] └─# nmap -sS -A -p- 192.168.103.202发现开放了22和80端口 2.web页面 打开80端口的web页面&#xff0c;是一张静态的图片&#xff0c;没什么价…

【Seata源码学习 】 扫描@GlobalTransaction注解 篇一

1. SeataAutoConfiguration 自动配置类的加载 基于SpringBoot的starter机制&#xff0c;在应用上下文启动时&#xff0c;会加载SeataAutoConfiguration自动配置类 # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfigurationio.seata.spring.boot.aut…

探寻知识的新路径——电大搜题助您开启学习新纪元

江西开放大学和广播电视大学一直以来都是许多自学者和职场人士追寻知识的圣地。然而&#xff0c;对于许多学子来说&#xff0c;学习的过程也常常充满了困惑和挑战。为了帮助这些学习者通过更高效、便捷的方式获取知识&#xff0c;江西开放大学推出了一款创新的学习工具——电大…

谈谈越来越无效的拥塞控制

简单看一个图&#xff1a; 它不是互联网本身&#xff0c;但这是典型网络的必要组件&#xff0c;它决定了 flow 如何从从一边流向另一边&#xff1a;一条 flow 经过交换节点通过 NIC 被导入一条链路前在 buffer 中排队。 现如今大多数工程师的工作都在折腾那个单独的盒子&…

231112-中文错别字识别与纠正问题的大模型与小模型调研

A. 引言 当前&#xff0c;以ChatGPT为代表的大语言模型&#xff08;Large Language Models, LLMs&#xff09;正引领着新一轮工业革命。ChatGPT最开始的研究领域隶属于NLP的一个子问题&#xff0c;其输入是text&#xff0c;输出也是text。在从文本输入到文本输出的诸多应用场景…

C语言从入门到精通之【概述】

#include指令和头文件 例如#include <stdio.h>&#xff0c;我们经常看到C文件最上面会有类似这样的语句&#xff0c;它的作用相当于把stdio.h文件中的所有内容都输入该行所在的位置。实际上&#xff0c;这是一种“拷贝-粘贴”的操作。 #include这行代码是一条C预处理器…

Smart Link 和 Monitor Link应用

定义 Smart Link常用于双上行链路组网&#xff0c;提高接入的可靠性。 Monitor Link通过监视上行接口&#xff0c;使下行接口同步上行接口状态&#xff0c;起到传递故障信息的作用。 Smart Link&#xff0c;又叫做备份链路。一个Smart Link由两个接口组成&#xff0c;其中一个…

木疙瘩踩坑日记-容易忽略的一些BUG

在一开始玩家务必很清楚这三个概念 图形&#xff1a;舞台上元素的最小单位。软件自带的以及外部导入的图片默认都是图形&#xff01;最朴素的元素&#xff01;可以添加预制动画、关键帧动画、进度动画&#xff08;软件自带的形状&#xff09; 元件&#xff1a;一个可以内部封…

高性能收发原始数据包的框架(Netmap)

一、Netmap 简介 Netmap 是一个高性能收发原始数据包的框架&#xff0c;由 Luigi Rizzo 等人开发完成&#xff0c;其包含了内核模块以及用户态库函数。其目标是&#xff0c;不修改现有操作系统软件以及不需要特殊硬件支持&#xff0c;实现用户态和网卡之间数据包的高性能传递。…

Git系列之分支与标签的使用及应用场景模拟

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是君易--鑨&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的博客专栏《Git实战开发》。&#x1f3af;&#x1f3af; &a…

【网络奇遇记】我和因特网的初相遇2 —— 三种交换方式

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、数据结构 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 前言一. 电路交换1.1 电路交换讲解1.2 电路交换实例 二. 分组交换1.1 分组交换讲解1.2 分组交换实例…

Go 14岁了

今天我们庆祝Go开源十四周年&#xff01;Go度过了美好的一年&#xff0c;发布了两个功能齐全的版本和其他重要的里程碑。 我们在2月份发布了Go 1.20&#xff0c;在8月份发布了Go 1.21&#xff0c;更多地关注实现改进而不是新的语言更改。 在Go 1.20中&#xff0c;我们预览了配置…

基于Python+Django的图书管理系统

项目介绍 图书是人类文明传播的一个重要方式&#xff0c;很多历史悠久的文明都是通过图书来进行传递的&#xff0c;虽然随着时代的进步电子信息技术发展很快&#xff0c;但是纸质图书的地位仍然是非常稳固的&#xff0c;为了能够让知识拥有更加快捷方便的传递方式我们开发了本…