C++ 说:“我们曾在家里尝试过。”
C++ says “We have try at home”

原始链接: https://devblogs.microsoft.com/oldnewthing/20251222-00/?p=111890

许多编程语言(Java、C#、Python、JavaScript)使用 `try...finally` 块来确保代码——例如清理操作——始终执行,无论是否发生异常。C++ 缺乏这种直接结构,而是通过析构函数来实现相同效果。像 Microsoft 的 `wil::scope_exit` 这样的库创建对象,当退出作用域时,其析构函数会运行指定的代码。 虽然核心原理在不同语言中相似,但 `finally` 块或析构函数 *内部* 的异常处理方式不同。Java、Python、JavaScript 和 C# 优先处理来自 `finally` 的异常,可能会丢失原始异常(尽管 Python 3.2 会将其作为上下文保留)。 C++ 更加严格:在异常展开期间,析构函数中的异常会导致程序终止。`wil::scope_exit` 遵循这一原则,在发生异常时终止程序,或提供记录/忽略的替代方案,但 *不* 像 Java 那样覆盖异常。因此,C++ 需要在清理代码中小心处理异常,以避免崩溃。

Hacker News 新闻 | 过去 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 C++ 说“我们已经在家里尝试过了”。(devblogs.microsoft.com/oldnewthing) 12 分,ibobev 发表于 3 小时前 | 隐藏 | 过去 | 收藏 | 1 条评论 jasode 1 分钟前 [–] 提交的标题缺少了博客文章的关键词“终于”。Raymond Chen 实际写的副标题是:“C++ 说“我们有 try…finally 在家里”。” 这是一个基于模因的雪克隆,“妈妈,我们可以得到 吗?我们已经在家里有 了”:https://www.google.com/search?q=%22we+have+x+at+home%22+meme 换句话说,“我们已经在家里冰箱里有了 C++ 的 'finally' 功能,它叫做 '析构函数'” 回复 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索:
相关文章

原文

Many languages¹ that have exceptions also have a finally clause, so you can write

try {
    ⟦ stuff ⟧
} finally {
    always();
}

A quick checks shows that this control structure exists in Java, C#, Python, JavaScript, but not C++.

C++ says, “We have try…finally at home.”

In C++, the way to get a block of code to execute when control leaves a block is to put it in a destructor, because destructors run when control leaves a block. This is the trick used by the Windows Implementation Library’s wil::scope_exit function: The lambda you provide is placed inside a custom object whose destructor runs the lambda.

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

⟦ stuff ⟧

Although the principle is the same, there are some quirks in how each language treats the case where the finally or destructor itself throws an exception.

If control leaves the guarded block without an exception, then any uncaught exception that occurs in the finally block or the destructor is thrown from the try block. All the languages seem to agree on this.

If control leaves the guarded block with an exception, and the finally block or destructor also throws an exception, then the behavior varies by language.

  • In Java, Python, JavaScript, and C# an exception thrown from a finally block overwrites the original exception, and the original exception is lost. Update: Adam Rosenfield points out that Python 3.2 now saves the original exception as the context of the new exception, but it is still the new exception that is thrown.
  • In C++, an exception thrown from a destructor triggers automatic program termination if the destructor is running due to an exception.²

So C++ gives you the ability to run code when control leaves a scope, but your code had better not allow an exception to escape if you know what’s good for you.

¹ The Microsoft compiler also supports the __try and __finally keywords for structured exception handling. These are, however, intended for C code. Don’t use them in C++ code because they interact with C++ exceptions in sometimes-confusing ways.

² This is why wil::scope_exit documents that it will terminate the process if the lambda throws an exception. There is an alternate function wil::scope_exit_log that logs and then ignores exceptions that are thrown from the lambda. There is no variation that gives you Java-like behavior.

联系我们 contact @ memedata.com