C++ says 'We have try at home.'
Source: Hacker News
Overview
Many languages¹ that have exceptions also have a finally clause, so you can write:
try {
// ⟦ stuff ⟧
} finally {
always();
}
A quick check shows that this control structure exists in Java, C#, Python, JavaScript, but not in C++.
C++ approach
C++ provides a way to execute code when control leaves a block by using a destructor, because destructors run when a scope is exited. This is the technique used by the Windows Implementation Library’s wil::scope_exit function: the lambda you supply is stored inside a custom object whose destructor runs the lambda.
auto ensure_cleanup = wil::scope_exit([&] { always(); });
/* ⟦ stuff ⟧ */
Exception‑handling quirks
Although the principle is the same, languages differ in how they treat the case where the finally block or destructor itself throws an exception.
No exception in the guarded block
If control leaves the guarded block without an exception, 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 behavior.
Exception in the guarded block and in the finally/destructor
| Language | Behavior when both the guarded block and the finally/destructor throw |
|---|---|
| Java, Python, JavaScript, C# | The exception thrown from the finally block overwrites the original exception, causing the original exception to be lost. Update: Python 3.2 now saves the original exception as the context of the new exception, but the new exception is still the one that propagates. |
| C++ | An exception thrown from a destructor terminates the program if the destructor is executing because another exception is already active.¹ |
So C++ lets you run code when a scope is exited, but that code must not allow an exception to escape if you want to avoid program termination.
Footnotes
¹ The Microsoft compiler also supports the __try and __finally keywords for Structured Exception Handling (SEH). These are intended for C code; using them in C++ can interact with C++ exceptions in confusing ways. See the discussion on oldnewthing.com.
² This is why wil::scope_exit documents that it will terminate the process if the lambda throws an exception. An alternative, wil::scope_exit_log, logs and then ignores exceptions thrown from the lambda. There is no variant that mimics Java‑like behavior.