目录
- C++ noexcept:
- 1、用途
- 2、用法
- 1、noexcept声明符的用法:
- 2、noexcept运算符的用法
- 异常传播
- 1、异常传播的定义
- 2、异常传播中的规则
- 3、异常传播的代价
C++ noexcept:
1、用途
C++11使用noexcept指明函数是否抛出异常:
若函数不抛异常,则可做编译优化
即便函数抛异常,也不再说明所抛异常类型(简化)
注意,C++03将throw(ExceptionType)放到函数后面,说明函数会抛出什么类型的异常,也被称为“异常规约”
java用 throws关键字做同样的事情
2、用法
1、noexcept声明符的用法:
void foo() noexcept {} //函数不抛异常void foo() noexcept(true) {} // noexcept(true)等价于noexceptvoid foo() {} // 可能会抛出异常void foo() noexcept(false) {} // noexcept(false)等价于什么也不写,可能会抛出异常
需要注意的地方:
1、noexcept不能用于区分重载函数。
2、如果我们声明函数时说了它不抛异常,但是又在noexcept函数中抛出异常,这就等于调用std::terminate(),终结程序的运行。
void f() { /* 潜在抛出异常 */ }
void g() noexcept {f(); // 合法,即 使 f 抛出 throw 42; // 合法,等效于调用 std::terminate
}
编译时会报警告:
主函数调用foo(),运行时程序会终止:
2、noexcept运算符的用法
bool noexcept( expression )
noexcept 运算符进行编译时检查,若表达式声明为不抛出任何异常则返回 true。
noexcept (may_throw())返回false,表明可能会抛异常。
noexcept (no_throw())返回true,表明不抛异常。
void may_throw();
void no_throw() noexcept;
int main() {std::cout << std::boolalpha<< "Is may_throw() noexcept? "<< noexcept (may_throw()) << '\n'<< "Is no_throw() noexcept? "<< noexcept (no_throw()) << '\n';
}
异常传播
1、异常传播的定义
嵌套的函数调用,每个函数中都有 try-catch 块,内层函数抛出异常,这时候会出现异常传播
如图,func3中出现了异常,如果没有被func2中的catch捕获到的话,异常会随着函数的返回,交给函数的上一级(func1)处理,如果func1也处理不了,则交给main函数处理,如果main函数处理不了,程序会崩溃。
需要注意的地方:
- try块中抛出异常的语句后面的语句
- catch的异常类型与所需匹配的异常实例的类型
2、异常传播中的规则
try-catch的执行规则
-
try块中的异常:抛异常的语句后的块代码都被跳过,并开始找exception handler的代码(即找catch代码)
-
找exception handler的流程:沿函数调用的链反向寻找(1) 按catch块的顺序对比,找到则执行catch块代码(2) 找不到,退出当前函数,将异常传给调用当前函数的函数
仍然以上图调用链为例:
Quiz: function3抛出
- Exception3,执行哪些statement?
执行Process ex3 -> statement6-> statement3-> statement4-> statement1-> statement2;- Exception2,执行哪些statement?
执行Process ex2 ->statement4-> statement1-> statement2;- Exception1,执行哪些statement?
执行Process ex1 -> statement2;- Exception0,执行哪些statement?
返回到主函数,程序崩溃
3、异常传播的代价
C++引入的异常处理会为程序带来额外开销和代价。
(1)项目中使用异常,需要考虑与未使用异常的第三方和旧项目代码的整合问题,避免出现一异常安全问题;
(2)异常使用不当,容易造成内存泄漏和程序崩溃,比如函数内抛出异常需要注意栈展开导致的内存泄露,析构函数抛出异常将程序置于不确定状态等;
(3)异常的跳转会彻底扰乱程序的执行流程并难以判断,给代码调试和维护增加难度;
(4)为保证写出异常安全的代码,往往需要借用C++其它特性,如智能指针,这又进一步加剧了代码可读性的恶化与程序的时空开销,包括编译时间的延长,运行效率的较低以及代码尺寸的增大。