views:

231

answers:

8

Each time I have seen the catch all statement:

try 
{
  // some code 
}
catch (...)
{

}

it has always been an abuse.

The arguments against using cache all clauses are obvious. It will catch anything including OS generated exceptions such as access violations. Since the exception handler can't know what it's dealing with, in most cases the exceptions will manifest as obscure log messages or some incoherent message box.

So catch(...) seems inherently evil.

But it is still implemented in C++ and other languages (Java, C#) implements similar mechanisms. So is there some cases when its usage is justified?

+5  A: 

the arguments against using cache all clauses are obvious , it will catch anything including OS generated exceptions such as access violation. since the exception handler can't know what its dealing with, in most cases the exceptions will manifest as obscure log message or some incoherent message box.

And if those same exceptions aren't caught you get... an incoherent message box.

catch(...) lets me at least present my own message box (and invoke custom logging, save a crash dump, etc.).

I think there are also reasonable uses of catch(...) in destructors. Destructors can't throw--well, I mean, they can throw, but if a destructor throws during stack unwinding due to an in-progress exception the program terminates, so they should not ever allow exceptions to escape. It is in general better to allow the first exception to continue to be unwound than to terminate the program.

Another situation is in a worker thread that can run arbitrary functions; generally you don't want an unceremonious crash if the task throws an exception. A catch(...) in the worker thread provides the opportunity for semi-orderly clean-up and shutdown.

DrPizza
What text would the message box display in a `catch(...)` block?..
Pavel Minaev
Probably something like "A severe error occured, the program will generate an error report and exit now."
mxp
The message will be `Call 911` :)
Kirill V. Lyadvinsky
It doesn't matter much, just something friendlier than the built-in Windows message.Another example might be in a worker thread scenario where arbitrary functions can be dispatched to the workers; making the workers swallow the exception and report back that they've done so (to allow an orderly termination of some kind) is probably better than allowing the default OS crash.
DrPizza
Yes, that runtime-provided message box is sooo bad for tests run during daily builds. catch(...), then write to the output - at least that is intercepted and the build proceeds.
sharptooth
@DrPizza: catch-all in worker threads is an important special use-case. You should probably include it in your answer.
Konrad Rudolph
@Konrad Rudolph: done!
DrPizza
eh, try catch in destructors is a mute point since the act of throwing whilst in a destructor will likely get you immediately terminated by your runtime. As usual, its platform and context dependent, but by the spec its a no-no and there are platforms that do carefully do the accounting to stop you doing it. catch(...) won't save you, execution won't even reach that point.
Will
@Will: I refer you to section 15.2 paragraph 3 of the 2003 C++ specification. In short, you're wrong: terminate is only called when the exception escapes the destructor. try/catch within a destructor is perfectly allowed. What isn't allowed is for the exception to leave the scope of the destructor. This is why the standard explicitly recommends catching exceptions and stopping them from propagating.
DrPizza
+3  A: 

The case where it's justified in general is when you log the exception (or do something similar) or do some cleanup, and then immediately rethrow.

In C++ in particular, logging in a catch(...) block is pretty pointless since you don't have any way to obtain the exception, and cleanup is pointless because you should be using RAII for that. Using it in destructors seems to be about the only legitimate case.

Pavel Minaev
+3  A: 

catch(...) has been useful for me in two circumstances, both of which are unjustified (I can't even remember the second)

The first is my overall application safety. While throwing exceptions that don't derive from std::exception is a No-No, I have one just in case in my main() function:

int execute(void); // real program lies here

int main(void)
{
    try
    {
        return execute();
    }
    catch(const std::exception& e)
    {
        // or similar
        std::cerr << "Unhandled exception: " << e.what() << std::endl;
        return EXIT_FAILURE;
    }
    catch(...)
    {
        std::cerr << "Unknown exception!" << std::endl;
        return EXIT_FAILURE;
    }
}

Now, it's only there "just in case", and it's not really justified. There should be no reason to ever enter that catch clause, as that would mean somebody has done a Bad Thing. Observe how useless the statement really is; "Something bad happened, no clue what!" It's only a step above just crashing in the first place.

The second use might be in destructors or some other function that needs to do manual management before letting the exception propagate. That's not really a justification either, as things should clean themselves up safely with RAII. But I may have used it once or twice for some reason I can't recall, and I can't see a reason to ever do so again.

GMan
exceptions cannot be thrown in destructors, and catches can't catch exceptions either since the thread terminates abruptly
Will
http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.3 is a good link. In the RAII world, how do you know you're not unwinding in your destructor already?
Will
@Will: I dunno where you've got this idea, but see section 15.2 paragraph 3 of the 2003 C++ specification, or even ready your own link. Exceptions aren't allowed to ESCAPE FROM a destructor, but they can be THROWN WITHIN a destructor--they just have to be caught there, too. And you know if you're unwinding already because std::uncaught_exception() returns true.
DrPizza
+5  A: 

(1) It's not true that the statement will catch OS exceptions. Your use of the term "Access Violation" betrays a Windows background; it was true for older MSVC++ versions.

(2) Regardsless, the catch-all behavior is useful for threads with specific purposes. Catching the failure allows the thread to report it failed. Without it, the other parts of the program need to deal with the possibility of a thread just disappearing. It also allows you to log which thread failed, and the arguments used to start the thread.

MSalters
With the MS compiler on Windows, whether structured exceptions are caught by catch (...) depends on the /EH compiler switch. /EHa will catch them, /EHsc will not. Not sure which one is the default
sbk
+1  A: 

catch (...) allows you to write code in which you can legitimately claim a guarantee that your code will not crash even when you are not in long term complete control of the submodules your code depends on. Your claim is tantamount to claiming that this semantic cannot be used except as a means of abuse. Maybe so, but military specifications may differ from you on this issue.

Paul Hsieh
not remotely true surely? Those submodules can go trashing your heap or anything else nasty and its unrecoverable.
Will
Obviously, you require that the sub-modules are legal with respect to the C++ language -- you can't make any kinds of guarantees outside of that. But in C++ throwing random stuff that the caller is unaware of is considered legal. That can cause your program to fail without some sort of catch-all.
Paul Hsieh
+2  A: 
  1. try {...} catch (...) is needed around body of callback function which is called from code that doesn't understand C++ exceptions (usually C library).

    Otherwise, if some C++ library you use throws an exception that doesn't derive from std::exception, it will probably cause calling code to crash or corrupt its internal state.
    Instead you should catch this exception and either finish program immediately or return some error code (meaning "we are doomed and I don't know why", but it's still better then letting C++ exception to pass through).

  2. Around thread procedure. Mostly because of the same reason as 1. And because otherwise thread failure would pass unnoticed.

Tomek Szpakowicz
+3  A: 

In addition to what other posters have already said, I'd like to mention one nice point from the C++ Standard:

If no matching handler is found in a program, the function std::terminate() is called; whether or not the stack is unwound before this call to std::terminate() is implementation-defined.

(15.3/9)

This means that main() and every thread function must be wrapped in a catch-all handler; otherwise, one can't even be sure that destructors for automatic objects will be called if an uncaught exception is thrown.

atzz
That is a rather disappointing design decision. Fortunately, I think pretty much any implementation is likely to be sensible, but still, it justifies a top-level catch(...) handler in every thread of execution (including the main one).
DrPizza
A: 

catch(...) is necessary in the absence of the finally clause as found in other languages:

try {
  ...
} catch(...) {
  cleanup...
  throw;
}

The alternative - making stack objects to 'own' everything - is often much more code and less readable and maintainable. The platform API is often C, and does not come with it conveniently bundled.

It is also useful around plugin code that you do not control or simply do not trust from a stability perspective. It won't stop them crashing, but it might keep things a little saner.

Finally, there are times when you really do not care about the outcome of something.

Will
Did you just suggest RAII is not a Good Thing?
GMan
I think I said there were times when catch(...) was a more maintainable alternative.
Will
What's more maintainable than not maintaining at all?
GMan
well I've used catch(...) around mixes of epoll and other native APIs; the alternative would be to make a class to own a handle and ... well it'd be a lot of code and the locality of source reference would be blown. RAII is great if designed in from the start. Its not something that is always thoughtfully provided by others, and sometimes a simple close(handle) or something in a catch(...) { .. throw; } is a very tidy way to clean up. You should try it some time!
Will
A handle wrapper may be more code but in the end it's much simpler. A `catch(...)` might seem like a good intermediate solution, though.
GMan
How does that work? The catch block won't execute if no exception is thrown, so you need to perform your clean up within the try block too.
DrPizza
Destructor's will be called automatically on stack-unwinding. That is, no `try/catch/throw` in the first place. Let the objects clean themselves up as the exception propagates.
GMan
Yes, I am asking Will how his post is meant to work--you can't just put cleanup in the catch(...), it'll never be called in non-exceptional circumstances. I know how destructors and RAII work!
DrPizza
Oh, I see haha. :) My mistake.
GMan