跳转至

Week13 Exception

异常(Exception)指的是程序在运行时遇到无法正常处理的问题时的一种机制。

其核心思想在于,当问题发生时,当前代码可能不知道如何解决,但它知道不能继续正常执行。异常机制允许程序暂停当前操作,将问题“抛”给能够处理它的代码。

首先需要强调的是,异常是运行时机制(针对run-time error),在程序运行时触发,用于处理运行时错误(比如文件无法打开、内存分配失败、数组越界等),C++编译器不会在编译时检查异常是否会发生,而是将异常处理逻辑留到运行时执行。

抛出异常throw

throw关键字用于抛出异常对象,暂停当前代码执行,并将控制权传递给调用栈中能够处理该异常的catch块,throw的使用有以下几点规则:

  • 抛出任意类型throw可以抛出任何类型的对象(包括基本类型、自定义类、标准库异常等等),但是我们推荐使用自定义异常类或std::exception的派生类
  • 抛出后中断throw执行后,当前函数立即停止,控制权沿调用栈向上传播。
  • 异常对象拷贝:抛出的对象会被复制(除非是通过引用捕获的),因此应确保对象支持拷贝或通过引用捕获

try监控可能抛出异常的代码

try块包裹可能抛出异常的代码,告诉C++运行时在这些代码中监视异常,其使用也有以下几点规则:

  • try后面必须至少跟一个catch块,否则编译器会报错
  • 只监控try块内的代码,块外代码不受影响
  • try块会引入运行时开销

catch捕获和处理异常

catch块用于捕获特定类型的异常,并执行相应的错误处理逻辑,其有以下几点规则

  • 按类型捕获:catch块指定捕获的异常类型,可以是具体类型、基类或...(捕获所有异常)
  • catch块按声明顺序检查,优先匹配精确类型,然后尝试基类转换,最后匹配...
  • catch块中可以使用throw,重新抛出当前异常
  • 推荐使用catch(Type& e)避免对象切片

异常对象

异常对象携带错误信息,能够帮助调用者了解问题原因

异常对象通常继承自std::exception或其派生类,提供what()方法返回错误描述;

标准库异常

标准库异常在使用的时候需要#include<stdexcept>,常见的标准库异常包括:

  • std::bad_alloc:内存分配失败
  • std::out_of_range:索引越界
  • std::runtime_error:通用运行时错误

栈展开(Stack Unwinding)

当异常抛出后,C++会沿调用栈向上寻找匹配的catch块,在此过程中,自动销毁栈上对象(调用其析构函数),确保资源正确释放

栈展开的规则有如下几点:

  • 自动清理:栈上对象的析构函数会在异常传播时自动调用
  • 析构函数不抛异常:如果析构函数在栈展开期间抛出异常,会导致std::terminate()

评论