异常处理

错误

  • 语法错误:编译器解决
  • 逻辑错误:测试解决

异常

  • 运行环境造成。如内存不足、文件操作失败等
  • 特征
    • 可以预见
    • 无法避免
  • 异常处理:提高程序鲁棒性

异常处理方法

传统的方法是,使用函数参数或者返回值来标识是否发生异常、发生什么异常。

函数调用者检查参数或者返回值来确定异常,并处理异常

这样需要逐层返回。并且对于一些特殊的情况无法处理,比如构造函数发生异常。


C++ 异常处理机制

try

监控语句序列中是否发生异常。

try{
	statements to monitor
}

throw

try 中检测到异常时,抛出异常。

throw expression

catch

捕获异常并处理。try 后可以跟随多个 catch 来捕获不同类型的异常。

catch (ExceptionType e){
	deal with exception...
}

异常处理的嵌套

抛出的异常会在调用链中自下往上捕获。

最终还未被捕获的异常,由系统的 abort 处理。

异常类间的继承

在捕获一系列有继承关系的异常类对象的时候,需要注意:

  • 引用传递异常对象。

即:

try
{...}
catch(Exception1 &e1){...}
catch(Exception2 &e2){...}

如果直接传异常对象,容易发生对象切片。

class EBase {};
class EDerived: public EBase {};

void f(EBase e) {
	throw e;
}

EDerived e;
try {
	f(e);  // Object Slicing, throwing EBase instead of EDerived
}
catch(EDerived e) { cout<<"Derived"; }
catch(EBase e) { cout<<"Base"; }  // e caught here
  • 按 “从最派生的类到最基的类” 的顺序来捕获

catch 是按声明顺序捕获的。

派生类对象可以被基类的 catch 捕获。

基类在前面的话,后面的派生类会无法捕获。

无参数 throw

将捕获到的异常对象重新抛掷出去

catch(int) { throw; }