I'm wondering a bit about C++ try/catch/finally blocks. I've seen these commands with two underscores like __try. But MVSC 2010 projects also run without the underscores. So when do you need these underscores?
On Windows, exceptions are supported at the operating system level. Called Structured Exception Handling (SEH), they are the rough equivalent to Unix signals. Compilers that generate code for Windows typically take advantage of this, they use the SEH infrastructure to implement C++ exceptions.
In keeping with the C++ standard, the throw and catch keywords only ever throw and catch C++ exceptions. The corresponding SEH exception code for the MSVC compiler is 0xe06d7363. The last 3 bytes are the ASCII code for "msc".
Unifying it with the operating system support also means that C++ destructors will be called during stack unwinding for an SEH exception. The code that does the unwinding is inside Windows and treats the SEH raised by a throw the exact same way as any SEH. However, the Microsoft compiler has an optimization that tries to avoid generating the code required that ensures that destructors are called in all cases. If it can prove that there's no throw statement inside the scope block that controls the object's lifetime then it skips the registration code. This is not compatible with asynchronous SEH exceptions, you should use the /EHa compile option to suppress this optimization if you intend to catch SEH exceptions.
There are a lot of SEH exception types. The ones that can be generated by the operating system are listed in the ntstatus.h SDK header file. In addition, you might interop with code that uses SEH to implement their own exception handling, they will use their own exception code. Like .NET, managed exceptions use the 0xe0434f4d ("com") exception code.
To catch SEH exceptions in a C++ program, you must use the non-standard __try keyword. The __except keyword is analogous to the C++ catch keyword. It has more capabilities, you specify an exception filter expression that determines whether or not an active exception should be caught. Anything is possible, but you typically only look at the passed exception information to see if you're interested in handling it. The __finally keyword lets you write code that runs after the exception is handled. No equivalent for that in C++ but not uncommon in other languages.
All of this is fairly poorly documented as pointed out in the comments. The proof is in the pudding. Here's an example program that you can play with. It demonstrates how SEH exceptions still allows for C++ destructors to be called, provided you compile with /EHa and how C++ exceptions are implemented on top of SEH. MSVC compiler required, run with Ctrl+F5 to avoid the debugger being helpful:
#include "stdafx.h"
#include <windows.h>
#include <iostream>
// NOTE: the value of the C/C++, Code Generation, Enable C++ Exceptions setting in important
// Try it both with /EHsc (the default) and /EHa to see the difference
class Example {
public:
~Example() { std::cout << "destructed" << std::endl; }
};
int filterException(int code, PEXCEPTION_POINTERS ex) {
std::cout << "Filtering " << std::hex << code << std::endl;
return EXCEPTION_EXECUTE_HANDLER;
}
void testProcessorFault() {
Example e;
int* p = 0;
*p = 42;
}
void testCppException() {
Example e;
throw 42;
}
int main()
{
__try {
testProcessorFault();
}
__except(filterException(GetExceptionCode(), GetExceptionInformation())) {
std::cout << "caught" << std::endl;
}
__try {
testCppException();
}
__except(filterException(GetExceptionCode(), GetExceptionInformation())) {
std::cout << "caught" << std::endl;
}
return 0;
}
Output:
Filtering c0000005
destructed
caught
Filtering e06d7363
destructed
caught
__finally
in a C++ program. Having destructors might even be the reason, why there is no dedicated keyword for always run regardless of exceptions thrown code. –
Fraktur __try
/ __except
is for catching SEH (windows generated errors) not for catching general exceptions.
try
/ catch
is what the C++ standard specifies for handling general C++ exceptions.
For the standard C++ code you write you should always use try
/ catch
and not __try
/ __except
Also, finally
is not C++ Standard specified construct, It works for you because it is a Microsoft compiler extension.
/EHa
(Yes With SEH Exceptions) is use try/catch will handle both: C++ and SEH exceptions. The downside is that catch(...)
will handle SEH, but you cannot know exception code. Destructor will be called when EHa
is used. Both try
and __try
cannot be mixed in same function. Therefore it is best to have two functions (one calling another): One handling try
and another handling __try
(Without /EHa
) –
Trexler __try/__except
is Microsoft specific If you want your code to be compilable with other compilers (for examplec g++) (or) in another OS avoid using them, and stick with the standard try/catch
statements
© 2022 - 2024 — McMap. All rights reserved.
finally
is not in C++ and is really kind of pointless for properly written C++ code. – Rothsteinfinally
is pointless because RAII is a better way of doing it in almost every case andscope_guard
takes care of the remaining 0.1%. – RothsteinTransaction * t = manager->BegintTransaction()
; try { t->Write("Foo");} catch (...) { LogError(); throw; } finally { manager->CloseTransaction(t); }` This way, you don't need to close the transaction in both thetry
block and in thecatch
block as well, just before re-throwing the exception. – Larderfinally
. This isn't standard yet but here's the proposal, and you can use existing 3rd-party libs. – Rothstein