C++ 栈展开
Stack Unwinding
当程序抛出一个异常时,程序暂停当前函数的执行过程并立即开始查找(look up)最邻近的与异常匹配的 catch 子句。
- 如果查找到一个匹配的 catch 子句,异常从它的抛出点开始“向上”传递到匹配的 catch 子句。异常传递过程中,当退出了某些作用域时,该作用域内异常发生前创建的局部对象会被销毁,按照与创建时相反的顺序依次销毁,对于类对象,销毁时会调用它的析构函数。上述过程称为栈展开(stack unwinding)。示例程序见 Cpp-Primer/Ch18_01_StackUnwinding.cpp at main · ltimaginea/Cpp-Primer · GitHub 。
- 如果没有查找到匹配的 catch 子句,即异常没有被捕获,程序将调用标准库函数 std::terminate ,它将终止当前的程序。默认情况下, std::terminate 会调用 std::abort 。出于底层操作系统方面的原因,当调用 std::terminate 时局部变量的析构函数是否会被调用是由具体C++实现所决定的。所以当程序因未捕获的异常而终止时,是否调用异常发生前创建的局部对象的析构函数是依赖于具体实现的(一方面,经过测试,对于 GNU g++ 9.3.0 ,执行和 gdb 调试时都不会调用析构函数;对于 Visual Studio 2022 MSVC ,“
Ctrl+F5
执行(不调试)”时不会调用析构函数,但在“F5
调试”时,当报错“未经处理的异常”时,选择“F5
继续”,结果会调用析构函数;另一方面,如果我们使用 std::set_terminate 为 std::terminate 安装新的 std::terminate_handler ,那么就有可能调用析构函数了,比如以