C++异常 abnormal
-
基本语法
void run() { /* 第一次抛出 */ if (error) { throw; } } int call() { try { /* 复合语句 */ run(); } catch (int e) { /* 异常类型声明 */ /* 复合语句 */ /* 第二次抛出,接受到异常, 可以不处理继续向外扔 */ 处理异常 or throw 继续抛出 } catch (类型 (形参)){ /* 复合语句 */ } catch (...) { /* 复合语句 */ 未知异常 or throw 继续抛出 } return 0; } int main() { call(); }
-
例1
#include <iostream> void divide(int x, int y) { if (y == 0) { throw x; } std::cout << "result = " << x / y << std::endl; } int main() { try { divide(10 ,0); } catch (int e) { std::cout << e << "被零除" << std::endl; } catch (...) { std::cout << "其他异常" << std::endl; } return 0; }
-
异常结论
- 若有异常则通过throw操作创建一个异常对象并抛出
- 将可能抛出异常的程序段嵌套在try块之中,控制通过正常的顺序到达try语句,然后执行try块内的保护段
- 如果在保护段执行期间没有引发异常,那么跟在try块后的catch子句就不执行,则跳过try catch块继续执行
- catch子句按其在try块后出现的顺序被检查,匹配到catch子句将捕获并处理异常(或基础抛出)
- 如果匹配的处理器未找到,则运行函数terminate将被自动调用,其缺省功能是调用abort终止程序
- 处理不了的异常,可以在catch的最后一个分支,使用throw语法,向上抛出
-
栈解退 (Stack unwinding)
异常被抛出后,从进入try块起,到异常被抛掷前,这期间在栈上的构造的所有对象,都会被自动析构。析构的顺序与构造的顺序相反。这一过程称为栈解退(unwinding)
#include <iostream> using namespace std; class T { public: T(int x = 0, int y = 1) { this->x = x; this->y = y; cout << "construct\n"; } ~T() { cout << "deconstruct\n"; } private: int x; int y; }; void divide() { T t1(10, 2), t2(20, 1); cout << "throw abnormal\n"; throw 1; } int main() { try { divide(); } catch (int e) { cout << "integer type abnormal\n"; } catch (...) { cout << "unknow abnormal\n"; } return 0; } /* 输出 */ /* construct construct throw abnormal deconstruct deconstruct integer type abnormal */
-
异常规范与C++11
异常规范(exception specification)是C++98新增的一项功能,但是在C++11被摒弃,它的语法如下
//1) 为了加强可读性,可以在函数声明中列出可能抛出的所有异常, void func() throw(A, B, C, D); // 这个函数只抛出类型为A B C D及其子类型的异常 // 2) 如果在函数声明中没有包含异常接口声明,则此函数可以抛掷任何类型的异常,例如 void func(); // 函数func可抛出任何类型异常 // 3) 一个不抛掷任何类型异常的函数可以声明为: void func() throw(); // 函数func不抛出任何异常 // 4) 如果一个函数抛出了它的异常接口声明所不允许抛出的异常,unexpected函数会被调用,该函数默认行为调用teminate函数终止程序
C++11支持一种特殊的异常规范:关键字noexcept指出函数不会引发异常
double func() noexcept; // 指出func不会引发异常
-
异常类型&异常变量的声明周期
- 如果接收异常时 使用一个异常变量,则拷贝构造异常变量
- 如果使用引用,会使用throw时的那个对象
- 如果使用指针,指针可以和引用元素一起使用,但是引用/元素不可以一起使用