I have some code that I've inherited from someone very clever where they like to use gotos to leave the try block, jumping completely around the catch blocks.
It definitely works, and I suspect this is legal (I think that the C++ standard says that on exit from a scope, everything gets cleaned up properly, and I assume that applies to whatever the compiler had to do to implement exceptions on my platform).
Is this really legit? It's NOT something I'd ever write (it's too clever by half), but it's clearly working, and I just want to understand why this is OK.
It can be legit and it depends on what the code does. For example I have written code that jumps out of a catch block, and it's used in a language's runtime library (for simplicity, the code that uses the runtime library does not implement the itanium exception handling, but is implemented using longjmp/setjmp). The runtime library however, through the C++ exceptions, does use it; and a mechanism is needed to cleanly transfer control between them.
try {
doSomethingThatMayFail();
} catch(DiagnosticException&) {
goto unwind;
}
if(0) {
unwind:
longjmp(&lastSafePoint, 0);
}
I put this into a macro so that it's very convenient to write. The goto
here is necessary to cleanup resources allocated during exception handling of the diagnostic exception.
As always, don't say "NEVER use this feature". Every use must be carefully thought about, instead.
Standard Says yes, it's legal & well-defined:
On exit from a scope (however accomplished), destructors (12.4) are called for all constructed objects with automatic storage duration (3.7.2) (named objects or temporaries) that are declared in that scope, in the reverse order of their declaration. Transfer out of a loop, out of a block, or back past an initialized variable with automatic storage duration involves the destruction of variables with automatic storage duration that are in scope at the point transferred from but not at the point transferred to. (See 6.7 for transfers into blocks). [Note: However, the program can be terminated (by calling exit() or abort()(18.3), for example) without destroying class objects with automatic storage duration. ]
I choose not to comment on the religious implications of using goto
in the first place.
Even more specifically than the C++03 standard's section on jump statements, it says this about try-blocks in the "Exception handling" clause (15/2):
A goto, break, return, or continue statement can be used to transfer control out of a try block or handler. When this happens, each variable declared in the try block will be destroyed in the context that directly contains its declaration.
C++11 contains the same wording.
Note however, that's it's not OK to jump into a try-block using a goto
(or switch
):
A goto or switch statement shall not be used to transfer control into a try block or into a handler.
It's legal. It's bad code. Don't do it. Don't use goto
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With