31

I'm wondering which is the better way to catch exceptions that I throw: is it a __try / __except block or a try / catch block?

I'm writing in C++ and the program will only be used on Windows, so portability is not an issue.

Thanks!

Zain Rizvi
  • 23,586
  • 22
  • 91
  • 133

5 Answers5

45

They are two very different things. try/catch are the familiar C++ keywords you know. __try/__except is used to catch SEH exceptions. Exceptions raised by Windows itself, like DivisionByZero or AccessViolation. It is well described in the MSDN Library article for it.

You can also use it to catch C++ exception because it leverages the Windows SEH feature. You however can't get the thrown exception object out of it so there will be zero context if you actually want the handle the exception. Which is madness. The number one approach is to not ever catch SEH exceptions, they are always gross. If you do need to marry the two then use _set_se_translator() to convert the SEH exception to a C++ exception.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
19

You should use a try/catch block.

As others have already answered, __try / __except is for catching SEH (windows generated errors) not for catching general exceptions.

Most importantly, __try and __catch may not run C++ destructors or correctly unwind the stack when an exception is thrown.

Except in rare cases, you should never try to catch SEH exceptions.

EDIT: Well, I was positive on this (it's what I've always been told), but @Hans says that apparently there is a compiler switch you can use to change this. I think the docs on /EHa are misleading, or at least incomplete, on what happens here. If someone finds definitive docs which prove this wrong, I'll happily remove this answer.

Even if it turns out this is false, you should still use try and catch simply because they are standard, while __try and __except are not.

Billy ONeal
  • 104,103
  • 58
  • 317
  • 552
  • So it doesn't unwind the stack? That means that it's probably a really bad idea to use `__try`/`__except` as anything other than a crash reporting system, whereas it's common to be able to recover from an exception in a `try`/`catch` block. – David Thornley Sep 16 '10 at 21:08
  • 2
    @David: That is correct. `__try` and `__except` are strictly a C based API/ABI. – Billy ONeal Sep 16 '10 at 21:15
  • The only good uses for it I've seen have been dealing with what amounted to bugs in Windows itself (such as what used to happen when you tried to copy a device). Arguably they're always indicative of somewhere where Windows should have caught the exception for you and translated it into an error. (The way they work is horrific too, and very very x86-specific…) – Donal Fellows Sep 16 '10 at 21:24
  • 7
    That's not accurate. Compiling with /EHa guarantees C++ destructor calls during stack unwinding. – Hans Passant Sep 17 '10 at 09:12
  • 1
    @Hans: Can you find documentation to that effect? My understanding of `/EHa` is merely that it allows C++ exception handling constructs (when you use `try` and `catch`) to catch SEH exceptions, but that the C++ stack is still not correctly unwound when `__try` and `__except` are used. – Billy ONeal Sep 17 '10 at 14:38
  • 2
    The /EH documentation is all there is. Yes, it isn't great. /EHa suppresses a compiler optimization that omits exception cleanup handlers when the compiler detects that none of the emitted code can throw a C++ exception. You can see them when you look at the machine code. – Hans Passant Sep 17 '10 at 14:45
  • I don't think I agree with this answer...this seems to work just fine for me in terms of catching C++ exceptions: __try { for (int *i = 0; *i < 100; i++) { *i = 10000; } } __except (FatalExceptionFilter(GetExceptionInformation(), GetExceptionCode())) { } Am I missing something here? – Alexandru Mar 19 '14 at 03:22
  • 1
    @Alex: `__except` can catch C++ exceptions; but my understanding is that it is not guaranteed to provide C++ stack unwind semantics while doing so. Except, as Hans claims, under `/EHa`. (Please please please don't use `/EHa`) – Billy ONeal Mar 19 '14 at 03:28
  • There's times where you don't want it to unwind the stack, specifically because you wanna catch the stack trace exactly where a problem happens on an application crash :) – Alexandru Mar 19 '14 at 10:55
  • @Alexandru: IF you want a stack trace you should let the application crash, and grab the minidump. The app generating its own stack trace requires symbols to be available, and those should generally speaking not be shipped with the app. – Billy ONeal Mar 20 '14 at 01:03
  • @BillyONeal Its true, shipping PDB's would make it easier to reverse-engineer your code. In cases where your solutions are hosted, it should be alright. If someone's going to reverse engineer your code, they'd probably be able to do it regardless...it just won't be as close of a match to the original. :) – Alexandru Mar 20 '14 at 01:27
  • @Alexandru: No, I'm not saying due to reverse engineering. I'm saying because you're burning 3x the drive space you need to burn for your app by forcing all your customers to install .pdbs. Having the app try to generate its own stack trace is like having a train where a car comes off the tracks, and while the train is still running at 80 miles an hour trying to figure out the root cause. Don't do that. Stop the train (crash) and figure out the problem afterward. – Billy ONeal Mar 21 '14 at 21:33
  • @BillyONeal That's a good point but space is cheap nowadays, so I'm not overly concerned about that. This is getting opinionated; I understand your point though. – Alexandru Mar 21 '14 at 21:37
6

__try/__except is designed for calling Win32 C code which doesn't support exceptions but does use a structured error code / handling mechanism. __try/__except will translate C errors into an exception block similar to C++ try/catch.

For more information, see this MSDN article.

Randolpho
  • 55,384
  • 17
  • 145
  • 179
4

Standard C++ uses try/catch blocks, so I would recommend using them, if you need the "standard" exception mechanism, based on standard C++ library.

However, if you plan to use Structured Exception Handling provided through Windows SDK (see here), then use __try/__except.

Cătălin Pitiș
  • 14,123
  • 2
  • 39
  • 62
2

Once you've thrown something, you no longer have much choice about how to catch it. If you throw C++ exceptions (i.e., with throw), then use try/catch. If you throw Windows exceptions (i.e., with RaiseException), then use __try/__except. Trying to mix them will just be adding unnecessary hassle to your life.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
  • 3
    But you should never thrown windows exceptions because they do not unwind the stack. – Billy ONeal Sep 16 '10 at 21:27
  • @BillyONeal apparently its the only way of setting a thread name pre-windows10 though: https://learn.microsoft.com/en-us/visualstudio/debugger/how-to-set-a-thread-name-in-native-code?view=vs-2019 – chacham15 May 20 '20 at 16:14
  • Stack unwinding is irrelevant in that case, @chacham, because you're only throwing to get the debugger's attention, not to change the program's flow. You immediately catch and discard the exception. The point remains, though, that you have no real choice about _how_ you catch that exception. You throw it with `RaiseException`, so you must catch it with `__except`. – Rob Kennedy May 21 '20 at 20:31
  • Sure, but "But you should never thrown windows exceptions" isnt entirely accurate. – chacham15 May 22 '20 at 20:30