December 22nd, 2025
intriguinglikeheartmind blown9 reactions

All the other cool languages have tryfinally. C++ says “We have tryfinally at home.”

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.

Topics

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

27 comments

Discussion is closed. Login to edit/delete existing comments.

Sort by :
  • Dave Brosius · Edited

    In Java you can avoid a finally exception from hiding a try exception, by moving the finally code to a try-with resources AutoCloseable. In this way if the try concludes normally and the exception is thrown by the autocloseable, then the autocloseable’s exception is the thing that’s thrown. If on the other hand the try throws an exception, the auto closeable’s exception is merely attached to the original exception as extra info. See Throwable.getSuppressed.

  • Ryan Johnson

    You’re throwing good money after bad. Ditch the problem system early and often.

  • Pejman Pakrooh

    It is correct, but only in not-very-common try-finally blocks and not in try-except-finally ones. In latter case we should store the first exception in a variable and then raise from it in finally

    • Kevin Norris

      If the exception is caught by the except and not re-raised, then by the time the finally clause executes, there’s no longer a “current exception.” We already caught and handled it. Chaining wouldn’t make sense, because the finally block did not replace an exception, it just raised a new one after we already disposed of the old one.

      If the exception is re-raised in the except clause, then it chains just like in try-finally.

  • Joshua Hudson

    (reply to Kevin Norris in case thread mode breaks again)

    You don’t need try/finally for that. You need try { } catch { throw; } . That solves that problem quite well indeed.