OOP10:Exceptions
第10章 Exceptions
10.1 Introduction
C++的原则
- 尽量在编译时,找出可能的错误
- 代码重用
但是在运行过程中,仍有错误发生,我们需要能够处理未来运行时,可能出现的错误
- 当出现错误的时候,程序不知道应该如何处理
- 但是程序知道必须要停止当前进程
- 让调用者caller处理异常
exception的优点
- 将代码简化
- 将描述想要执行的代码与执行的代码分开
10.2 语法
10.2.1 callee扔出异常
- throw出的是一个异常对象(class)
class VectorIndexError { |
10.2.2 caller处理异常
10.2.2.1 不管异常
int func() { |
10.2.2.2 处理异常 try… catch…
- catch处理哪一类异常,是根据catch后面的异常对象决定的
void outer() { |
10.2.2.3 将异常传递下去
void outer2(){ |
10.2.2.4 处理任意类型的异常
- ...代表任意类型的异常
void outer3() { |
10.2.3 总结
throw扔出异常
- 处理器会沿着调用链,找到第一个能够处理异常的程序
- 在stack上的对象,会被正确的析构
throw exp;
- 扔出异常对象,便于caller处理
throw;
- 将捕获到的异常再扔出去
- 只能在catch块里面写
try block
- 一个try后面可以有任意多个catch
- 每个catch block处理不同的异常
- 如果没有对异常处理的代码,则可以不写try
catch
- 一个try后面可以有任意多个catch
- 会根据出现的顺序,判断使用哪一个handler
- 对于每一个handler
- 会先进行精准匹配
- 如果精准匹配不成功,会尝试类型转换:如果当前handler可以处理当前异常的父类,则会调用这个handler
- 最后判断当前handler是否处理…
- 因此,要将精确匹配的类型放在前面
class A{ |
10.2.4 异常类型的继承
class MathErr{ |
10.3 系统自带的异常
10.3.1 bad_alloc():new不成功
void func() { |
10.4 定义函数应该扔出的异常
- abc扔出的异常应该是MathErr,相当于要求abc函数应该只处理数学问题
- 在编译时,不会检查
- 在运行时,如果扔出的异常不是MathErr,会扔出unexpected异常
- 规定的异常类型可以是多个
void abc(int a) throw(MathErr){ |
10.5 异常与构造函数、析构函数
判断构造是否成功
- 使用一个uninitialized flag
- 将申请内存的操作延后到Init()函数
- 扔出一个异常
异常与构造函数
- 初始化所有成员对象
- 将所有的指针初始化为NULL
- 不进行申请资源的操作,如打开文件、申请内存、连接网络
- 在Init()函数中申请资源
异常与析构函数
- 由于析构函数本来就是退栈过程,因此不能在析构函数中扔出异常
- 如果扔出异常,会触发std::terminate()异常
- 通过异常退出析构函数,是不合法的
10.6 使用异常编程
throw的如果是new出的对象,要记着在catch中delete
try {
throw new Y();
} catch(Y* p) {
// whoops, forgot to delete..
}建议catch引用/指针,而不是对象
struct X {};
struct Y : public X {};
// 不要写成这样
try {
throw Y();
} catch(X x) {
// was it X or Y?
}
// 要使用引用or指针
try {
throw Y();
} catch(X &x) {
}如果一个异常没有被捕获,则会产生std::terminate()异常,terminate()也可以被拦截
void my_terminate(){ /* ... */}
...
set_terminate(my_terminate);
10.7 Exception的处理机制
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 华风夏韵!
评论