C++ says “我们在家尝试”

发布: (2025年12月28日 GMT+8 14:42)
3 min read

Source: Hacker News

Finally in other languages

许多拥有异常机制的语言¹也都有 finally 子句,因此你可以这样写

try {
    // stuff
} finally {
    always();
}

快速检查可以发现,这种控制结构在 Java、C#、Python、JavaScript 中都有,但 在 C++ 中有。

C++ approach

C++ 说:“我们在本地有 try…finally。”

在 C++ 中,让一段代码在控制离开块时执行的方式是把它放进析构函数,因为析构函数会在控制离开块时运行。这正是 Windows Implementation Library 的 wil::scope_exit 函数使用的技巧:你提供的 lambda 被放入一个自定义对象中,该对象的析构函数会执行该 lambda。

auto ensure_cleanup = wil::scope_exit([&] { always(); });

/* stuff */

Exception‑handling quirks

虽然原理相同,但每种语言对 finally(或析构函数)本身抛出异常的情况处理略有不同。

No exception in the guarded block

如果控制在没有异常的情况下离开受保护块,则在 finally 块或析构函数中出现的任何未捕获异常都会从 try 块抛出。所有语言似乎在这一点上都达成了一致。

Exception in both the guarded block and the finally/destructor

语言当受保护块和 finally/析构函数都抛出异常时的行为
Java、C#、Python、JavaScriptfinally 块抛出的异常 覆盖 原始异常;原始异常丢失。更新:Python 3.2 现在将原始异常保存为新异常的 context,但仍以新异常传播。
C++如果析构函数因另一个异常而运行时抛出异常,程序会终止。²

因此,C++ 让你能够在离开作用域时运行代码,但你的代码最好不要让异常逃逸,否则后果自负。

Footnotes

  1. Microsoft 编译器也支持用于结构化异常处理的 __try__finally 关键字。这些关键字面向 C 代码。不要在 C++ 代码中使用它们,因为它们会以有时令人困惑的方式与 C++ 异常交互。
  2. 这就是 wil::scope_exit 文档中说明如果 lambda 抛出异常会终止进程的原因。还有一个替代函数 wil::scope_exit_log,它会记录并忽略 lambda 抛出的异常。没有提供类似 Java 行为的变体。
Back to Blog

相关文章

阅读更多 »

C++ 说 “我们在家尝试”。

许多具有异常机制的语言¹也都有 finally 子句,所以你可以这样写: cpp try { // ⟦ stuff ⟧ } finally { always; } 快速检查表明,这种 co…

Go的秘密生活:错误处理

第12章:碎玻璃的声音 星期一的早晨,厚重的灰色雾气笼罩着整座城市。档案馆内部,寂静至极,随后被打破……