CppPrimer笔记 Chapter18 用于大型程序的工具
标签: Cpp
异常处理(18.1)
- 当执行一个
throw
时,跟在throw
后的语句将不再被执行,相反,程序的控制权从throw
转移到与之匹配的catch
模块.这意味着
- 沿着调用链的函数可能会提早退出
- 一旦程序开始执行异常处理代码,则沿着调用链创建的对象将被销毁
- 栈展开:沿着嵌套函数的调用链不断查找,直到找到了与异常匹配的
catch
子句,若一直没找到,退出main后查找过程终止. - 找到
catch
后,程序进入该子句并执行,完成后,找到与try
块关联的最后一个catch
子句之后的点,并从这里继续执行 - 栈展开过程中,会运行类类型的局部对象的析构函数.由于析构函数为自动执行,他们不应抛出异常.若抛出异常,函数本身没有捕获该异常,则程序终止.
- 异常时,可能构造函数只构造了一部分,数组或标准库正在初始化.这时要保证这部分元素正确地被销毁.像
new
的空间若在delete
前异常,则不会释放. - 编译器使用异常排除表达式对异常对象进行拷贝初始化.因此
throw
语句中的表达式必须有完全类型.必须含有一个可访问的析构与拷贝或移动构造函数. - 异常类型位于编译器管理的空间中,以确保无论最终调用的是哪个catch子句都能访问该空间.异常处理完毕后,异常对象被销毁.
- 防止抛出的指针在栈展开过程中被销毁.
- 通常情况下,若
catch
接受的异常与某个继承体系有关,则最好将该catch
的参数定义成引用类型 - catch匹配规则
- 允许从非常量向常量的类型转换
- 允许从派生类向基类的类型转换
- 数组被转换成指向数组(元素)类型的指针,函数被转换成指向该函数类型的指针.
其它的包括算数类型转换与类类型转换都不允许
- 若多个
catch
语句类型间存在着继承,则应该吧继承链最低端(派生类)放在前面,最顶端(基类)放在后面. - 利用
throw;
语句重新抛出.将当前的异常对象沿着调用链向上传递. - 重新抛出时,只有当
catch
异常声明是引用类型时我们对参数所做的改变才会被保留并继续传播 catch(...){}
语句捕获所有异常,一般与throw;
重新抛出一起使用,先自己执行局部能完成的工作没然后重新抛出异常
- 为了能处理初始化列表抛出的异常,将构造函数写成函数
try
语句块
B::B(initializer_list<int> il)try:data(make_shared<vector<int>>(il){}
catch(const bad_alloc&e){handle_out_of_memory(e);} - 利用
noexcept
表明函数不会抛出异常.应在函数所有声明语句与定义语句中出现.位置与使用如下
auto recoup(int) //const &&
throw()//final override =0
->int;
auto recoup(int) throw()->int{return 1;} - 若
noexcept
函数抛出了异常,编译器不会警告,程序会直接终止 noexpect说明符
常与noexpect
运算符一起使用.表明不抛出异常的依赖关系.
noexpect说明符
可接受一个可转成bool参数,若为true,则为不抛出异常.
noexpect运算符
是一元运算符,返回bool右值常量表达式.和sizeof一样,并不会求其运算对象的值.
`vodi f()noexcept(noexpect(g()));//f和g异常说明一致