C++笔记(9) 异常
程序有时会遇到运行阶段错误,导致程序无法正常走下去。对于这种问题,处理方法主要有:
1.调用abort()
Abort()函数原型位于头文件cstdlib,其典型实现是向标准错误流(即cerr使用的错误流)发送消息abnormal program termination(程序异常终止),然后中止程序。它还返回一个随实现而异的值,告诉操作系统,处理失败。abort()是否刷新文件缓存区取决于实现。如果愿意还可以用exit(),该函数刷新文件缓存区,但不显示消息。
2. 使用函数的返回值来指出问题
例如,ostream类的get(void)成员,通常返回下一个输入字符的ASCII码,但到达文件尾时,将返回特殊值EOF。
3.异常机制
对异常的处理有3个组成部分:
- 引发异常
- 使用处理程序捕获异常
- 使用try块
下面是一个实例,抛出一个除以零的异常,并在 catch 块中捕获该异常。
#include <iostream>
using namespace std; double division(int a, int b)
{
if( b == 0 )
{
throw "Division by zero condition!";//抛出异常
}
return (a/b);
} int main ()
{
int x = 50;
int y = 0;
double z = 0;
try {//start of try block
z = division(x, y);
cout << z << endl;
}//end of try block
catch (const char* msg) {//start of exception handler
cerr << msg << endl;
}//end of exception handler
return 0;
}
由于我们抛出了一个类型为 const char* 的异常,因此,当捕获该异常时,我们必须在 catch 块中使用 const char*。当上面的代码被编译和执行时,它会产生下列结果:
Division by zero condition!
如果在执行完try块中的语句后,没有引发任何异常,则程序跳过try后面的catch块,直接执行处理程序后面的第一条语句。
异常的特性:
1. 执行throw语句类似于执行返回语句,因为它也将中止函数的执行。但还是有些不同之处:
1)throw不是将控制权返回给调用程序,而是导致程序沿调用序列后退,直到找到包含try块的函数。
2)引发异常时,编译器总是创建一个临时拷贝,即使异常规范和catch块中指定的是引用。
class problem{...}
...
void super() throw (problem)
{
...
if(oh_no)
{
problem oops;
throw oops;//抛出的是oops的副本
...
}
}
try{
super();
}
catch(problem & p)//p是oops副本的引用,在函数super()执行完毕后,oops将不复存在
{
...
}
既然throw语句将生成副本,为什么代码中还要使用引用呢?
- 将引用作为返回值的通常原因是避免创建副本以提高效率
- 基类引用可以执行派生类对象
2. 基类引用能够捕获任何异常对象,而派生类对象只能捕获它所属类及从这个类派生而来的类的对象。引发的异常对象往往被第一个与之匹配的catch块捕获,所以,catch块的排列顺序应该与派生顺序相反。
3. 程序进行栈解退以回到能够捕捉异常的地方时。将释放栈中的自动存储变量。如果变量是类对象。将为该对象调用析构函数。但是在有 new 分配内存的程序中,因为异常而使函数终止,没能执行对应的delete,通常需要程序员在对应的catch块中补上对应delete。
C++ 标准的异常
C++ 提供了一系列标准的异常,定义在 <exception> 中,我们可以在程序中使用这些标准的异常。它们是以父子类层次结构组织起来的,如下所示:

下表是对上面层次结构中出现的每个异常的说明:
| 异常 | 描述 |
|---|---|
| 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 | 当发生数学下溢时,会抛出该异常。 |
异常何时会迷失方向
1. 意外异常:在带异常规范的函数中引发,但没有与规范列表中的某种异常匹配。
会先调用unexpected(),unexpected()调用terminate(),terminate()调用abort(),利用可以修改unexpected()的行为的set_unexpected()函数。
这些函数在头文件<exception>中声明:
typedef void (*unexpected_handler) ();//定义一个函数指针
unexpected_handler set_unexpected(unexpected_handler f) throw;//一个无参数 无返回 函数
void unexpected();
解决方案:
1)首先
#include <exception>
using namespace std;
2)自己定义一个替代函数
void myUnexpected()
{
throw std::bad_exception(); //bad_exception是exception派生
}
3)再程序中定义
set_unexpected(myUnexpected);
4)然后把bad_exception类型规范到函数中
double Argh (double,double) throw(out_of_bounds,bad_exception);
… try
{
x=Argh(a,b);
} catch (out_of_bounds & ex)
{……} catch (bad_exception & ex)
{……}
2. 未捕获异常:不是在函数中引发/函数没有异常规范,由于没有try块或匹配的catch块导致没有捕获。
未捕获异常不会直接导致程序终止,程序会先调用terminate(),默认情况下terminate()调用abort()。
也可以指定terminate()调用的函数,利用set_terminate()函数。
这些函数在头文件<exception>中声明:
set_terminate():
typedef void (*terminate_handler) ();//定义一个函数指针
terminate_handler set_terminate(terminate_handler f) throw;//一个无参数 无返回 函数
void terminate();
解决方案:
1)首先
#include <exception>
using namespace std;
2)写个自定义函数
void myQuit()
{
cout<<"..."<<endl;
exit(5);
}
3)在程序开头,将中止操作指定为调用该函数
set_terminate(myQuit);
源自:
1. 《C++ Primer Plus》15.3节
2. https://www.runoob.com/cplusplus/cpp-exceptions-handling.html
C++笔记(9) 异常的更多相关文章
- python学习笔记5_异常
python学习笔记5_异常 1.什么事异常 Python使用异常对象(exception object) 来表示异常情况.遇到错误会发生异常. 如果异常对象未被处理或被捕捉,程序就会用所谓的回溯(t ...
- 笔记-python异常信息输出
笔记-python异常信息输出 1. 异常信息输出 python异常捕获使用try-except-else-finally语句: 在except 语句中可以使用except as e,然后通 ...
- Windows内核读书笔记——Windows异常分发处理机制
本篇读书笔记主要参考自<深入解析Windows操作系统>和<软件调试>这两本书. IDT是处理异常,实现操作系统与CPU的交互的关口. 系统在初始化阶段会去填写这个结构. ID ...
- 斯坦福机器学习视频笔记 Week9 异常检测和高斯混合模型 Anomaly Detection
异常检测,广泛用于欺诈检测(例如“此信用卡被盗?”). 给定大量的数据点,我们有时可能想要找出哪些与平均值有显着差异. 例如,在制造中,我们可能想要检测缺陷或异常. 我们展示了如何使用高斯分布来建模数 ...
- [Java学习笔记] Java异常机制(也许是全网最独特视角)
Java 异常机制(也许是全网最独特视角) 一.Java中的"异常"指什么 什么是异常 一句话简单理解:异常是程序运行中的一些异常或者错误. (纯字面意思) Error类 和 Ex ...
- Java笔记:异常
Exception 类的层次 所有的异常类是从 java.lang.Exception 类继承的子类. Exception 类是 Throwable 类的子类.除了Exception类外,Throwa ...
- Effective Java 读书笔记之八 异常
一.只针对异常的情况才使用异常 1.类具有状态相关的方法时,可采用状态测试方法和可识别的返回值两个策略. 二.对可恢复的情况使用受检异常,对编程错误使用运行时异常 1.期望调用者能够适当恢复的情况,应 ...
- javase基础笔记4——异常/单例和类集框架
继承 extends final关键 多态 是在继承的基础上 接口 interface 异常 exception 包的访问可控制权限 private default protect public 异常 ...
- struts2 笔记03 异常支持、防止页面刷新和后退、方法验证
Struts2对异常支持(声明式异常.自动的异常处理), 异常处理(运行期异常事务自动回滚) 1. 自定义异常类,继承RuntimeException或Exception实现构造方法. 2. 配置异常 ...
- Java编程思想学习笔记_4(异常机制,容器)
一.finally语句注意的细节: 当涉及到break和continue语句的时候,finally字句也会得到执行. public class Test7 { public static void m ...
随机推荐
- Lattice高速下载器HW-USBN-2B 如何申请 license
如果用的芯片不是停产老旧芯片,Diamond programmer 是不需要 license 绑定支持的. 但是有些需要编程老旧的芯片.需要安装 Diamond programmer stand-al ...
- 力扣507(java)-完美数(简单)
题目: 对于一个 正整数,如果它和除了它自身以外的所有 正因子 之和相等,我们称它为 「完美数」. 给定一个 整数 n, 如果是完美数,返回 true:否则返回 false. 示例 1: 输入:num ...
- 【阿里云采购季】3月采购完,IT运维躺赢一年2
阿里云2020上云采购季正式上线啦!今年的采购季可以逛些啥? 采购季正式期时间: 3月2日-3月31日 在这段时间里,想买啥就买吧,别忘了把想买的产品加入购物车噢,特惠产品叠加购物车满减,更划算 ...
- IT人的年夜饭,也太香了吧
简介: 平时的IT人,奋战在修复bug前线,起早与贪黑齐飞,调休共假期待定.到了新春佳节,对于IT人来说,没有什么是比一顿年夜饭更让人熨贴肺腑的了.为了让废寝忘食编程序.闻机起早保运维的IT人过一个 ...
- 智能数据构建与管理平台Dataphin的前世今生:缘起
简介: 阿里巴巴提出的OneData方法论帮助企业捋清了数据全生命周期的管理思路,更将其植入到产品Dataphin(智能数据构建与管理)中,通过阿里云为企业提供服务. Dataphin 智能数据构建与 ...
- KubeMeet|聊聊新锐开源项目与云原生新的价值聚焦点
简介: 10 月 16 日上海,OAM/KubeVela.OpenKruise.OCM 三大开源项目的社区负责人.核心贡献者和企业用户将齐聚 KubeMeet,和现场 100 名开发者聊聊新的技术环 ...
- [GPT] Vue 的 methods 中使用了 addEventListener,如何在 addEventListener 的匿名函数参数中访问 Vue data 变量
在 Vue 的 methods 方法中使用 addEventListener时,你可以使用 箭头函数 来访问 Vue 实例的数据. 箭头函数不会创建自己的作用域,而是继承父级作用域的上下文.以下是 ...
- [FAQ] curl SSL_connect: SSL_ERROR_SYSCALL / wget Unable to establish SSL connection
当客户端访问 https 网站时遇到这些错误提示,通常问题出在服务器,而不是客户端. 因为你换一个 https 网站进行请求,可以验证这一点. 通过浏览器访问正常,大多数浏览器通过重试较低的 TLS ...
- NOIP2023游寄
Day -?? 模拟赛挂分. Day -18 模拟赛挂大分,挂分大于得分.(180/400,得分/标准分,下同) 连着挂了好多场了,感觉有点迷茫了. Day -17 模拟赛--AK了?(400/400 ...
- C++ lambda的重载
先说结论,lambda是不能重载的(至少到c++23依旧如此,以后会怎么样没人知道).而且即使代码完全一样的两个lambda也会有完全不同的类型. 但虽然不能直接实现lambda重载,我们有办法去模拟 ...