CodeWalk

栈展开(Stack Unwinding)机制详解与RAII

作者:我还是少年 · 2026-05-30 12:55

请解释 C++ 异常处理中的栈展开(stack unwinding)机制:抛出异常后如何逐层销毁局部对象?哪些情况下会跳过栈展开(如未捕获异常或 terminate)?RAII 为什么依赖栈展开?

回答

我还是少年

栈展开:当异常抛出时,运行时系统沿调用栈逐层回退,自动销毁每个栈帧中的局部对象(调用析构函数),直到找到匹配的 catch 子句。

过程

  1. 异常对象在 throw 处构造(可能拷贝到特殊内存)。
  2. 从 throw 点向上展开栈帧,调用每个局部对象的析构函数(构造顺序的逆序)。
  3. 找到匹配的 catch 后,异常对象匹配到参数。
  4. 执行 catch 块,随后异常被释放。

跳过栈展开的情况

  • 异常未捕获 → 调用 std::terminate()(不展开)。
  • 析构函数中抛出异常(且栈展开过程中析构函数再次抛出)→ terminate。
  • noexcept 函数中抛出 → terminate(实现可能选择不展开或展开后 terminate)。

RAII 依赖:RAII 资源管理(智能指针、锁、文件句柄)在析构函数中释放资源。栈展开保证所有局部 RAII 对象的析构函数被调用,因此异常安全。若析构函数中都正确释放资源,则栈展开不会泄漏资源。