Alon
Alon

Reputation: 4952

Is there an occasion where using catch all clause : catch (...) is justified?

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?

Upvotes: 5

Views: 803

Answers (8)

GManNickG
GManNickG

Reputation: 504133

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.

Upvotes: 2

Will
Will

Reputation: 75673

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.

Upvotes: -2

DrPizza
DrPizza

Reputation: 18360

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.

Upvotes: 4

atzz
atzz

Reputation: 18010

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.

Upvotes: 3

Tomek Szpakowicz
Tomek Szpakowicz

Reputation: 14522

  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.

Upvotes: 2

Paul Hsieh
Paul Hsieh

Reputation: 1526

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.

Upvotes: 1

MSalters
MSalters

Reputation: 180020

(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.

Upvotes: 6

Pavel Minaev
Pavel Minaev

Reputation: 101615

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.

Upvotes: 5

Related Questions