C++进阶 异常

一.异常的概念及使用

1.异常的概念

异常就是:

程序运行过程中发生了"不正常情况",程序通过一种特殊机制,把错误信息传递出去,再由其他地方统一处理。

例如:

  • 除数为 0
  • 文件打开失败
  • 内存申请失败
  • 数组越界
  • 网络连接失败

这些都属于异常情况。

没有异常时(传统方式)

比如:

调用:

这里的问题:

问题1:返回值可能冲突

比如:

结果也是:-1

到底是正常结果还是错误?

无法区分。

问题2:错误信息不够

返回:-1

无法知道:

  • 哪个函数错了
  • 为什么错
  • 错误位置
  • 怎么修复

只能查错误码。

C语言没有异常机制。

通常这样:

errno

系统错误编号。

例如:

2.异常的抛出和捕获

例如:

输出:捕获异常:10

throw执行后,后面的代码不会执行

例如:

输出:1

异常

当前调用链决定哪个catch处理异常

意思:

程序从当前函数开始向外层找。

例如:

输出:100

这叫异常传播

离throw最近且类型匹配的catch处理

例子:

输出:内部

如果内部类型不匹配:

继续向外传播

最终:外部

3.栈展开

正常函数调用:

异常发生:

程序不再正常返回。

当异常抛出后:
先检查当前函数有没有try

先看当前函数内部能不能处理。

例如:

输出:当前函数处理

当前函数没有catch

退出当前函数继续查找

调用:

发生:throw

查找:

输出:处理异常

这个过程就叫:

栈展开

沿调用栈不断退出。

退出函数时对象会析构 ,调用链创建对象都会销毁

输出:析构

捕获

异常退出也会释放资源。

类型不匹配继续向外找

如果:

则全部匹配

到main还没找到会调用标准库终止程序

例子:

输出可能:

找到catch以后程序继续执行

输出:处理

继续执行

继续的是:整个try-catch后面,不是回到 throw

4.查找匹配的处理代码

1.最常见情况:类型完全匹配

throw 什么类型,就用什么类型接。

如果不一致,继续向外传播。

2.有多个catch,选最近且匹配的

3.允许非const → const(权限缩小)

输出:成功

但是反方向不行:

因为权限放大了

4.数组→指针转换

数组允许退化成指针

输出:hello

发生数组退化

5.函数→函数指针转换

6.派生类异常可以用基类捕获

抛:

能捕获。

完整例子:

输出:除0

工程里:

统一:

处理所有异常。

这是标准写法。

7.catch(...) 捕获所有异常

一般main最后加catch(...)

匹配任意类型

输出:未知异常

但:

只能知道发生异常,不知道具体是什么异常

5.异常重新抛出

当前函数可能只能处理一部分异常,剩下的交给更外层统一处理。

语法:

这里没有对象。

表示:把当前正在处理的那个异常继续向外扔。

例子:

输出:内部处理

外部处理

为什么必须写 throw; 而不是 throw e;

表示:新抛出一个 e 的副本。

可能发生:

  • 再拷贝一次
  • 类型退化(对象切片)

结果:

叫:对象切片

正确:

表示:继续抛原来的异常对象

不会复制。

不会降级

重新抛出时会重新找catch

输出:最终处理

重新抛出时栈展开仍然发生

资源照样释放

6. 异常规范

一个函数会不会抛异常,能不能提前告诉调用者?

异常规范就是干这个的。

它本质上是一种:函数的异常承诺

告诉别人:

  • 我不会抛异常
  • 我可能抛哪些异常
  • 调用我需不需要准备 catch

假设有函数:

调用者看到:

不知道

会不会抛异常?

抛什么异常?

要不要try?

于是有异常规范,提前说明;

例如:

表示:

保证不抛异常

C++98 的异常规范

语法:

函数后面:

1.throw()

表示:不会抛异常

表示:

这个函数保证不抛异常

如果违反:

程序结束

2.throw(type1,type2...)

表示:允许抛这些类型。

表示:

允许:

为什么淘汰?

因为太麻烦。维护困难

C++11 用 noexcept 简化

表示:保证不抛异常

调用者知道安全,不会异常

编译器不会严格检查 noexcept

可能编译通过

但运行:

结果:

程序结束

noexcept 还能作为运算符

作用:

检查表达式是否可能异常。

返回:

输出:1

说明:

不会抛。

析构函数默认就是 noexcept

默认等价:

所以:

通常:

二.标准库的异常

标准库没有把异常设计成杂乱的 throw intthrow "error",而是设计了一套继承体系,统一用基类 std::exception 管理。

1.标准库异常继承结构

其中:

exception(根基类)

所有标准异常父类。

定义类似:

关键:

支持多态

2.what() 是干什么的

返回错误描述。

例如:

输出:数据库连接失败

发生动态绑定

实际上调用:

不是:

3.几个常见标准异常

bad_alloc(内存申请失败)

输出类似:

out_of_range(越界)

输出:

invalid_argument(参数错误)

输出:

相关推荐
WWJA王文举2 小时前
I²C通信完整流程详解:START、地址、ACK、数据、Repeated START和STOP一次讲透
c语言·开发语言
zhanghaha13142 小时前
Python进阶教程:6_JSON 数据解析 —— 新手完全指南
开发语言·python·json
ShineWinsu3 小时前
对于C++:C++11中lambda、function、bind的解析
c++·面试·笔试·开发·lambda·bind·function
码匠许师傅3 小时前
【C++ 面试真题】聊聊 C++ 的拷贝构造与拷贝赋值
java·c++·面试
qq_448011164 小时前
C语言中的动态内存分配
c语言·开发语言·php
旖旎夜光4 小时前
LeetCode 3:无重复字符的最长子串(滑动窗口) —— 题解
数据结构·c++·算法·leetcode·滑动窗口
汉字萌萌哒4 小时前
2024CSP-J入门级C++真题详解
开发语言·c++
arbboter5 小时前
【网络工具】NetProxy网络代理用户手册
开发语言·网络·c#·网络代理·网络异常·代理工具
hy.z_7775 小时前
【C++】13. 继承
c++
汉字萌萌哒6 小时前
2019CCF-CSP入门级C++试题解析
java·开发语言·c++