views:

348

answers:

6

Hi,

I found some code in a project which looks like that :

int main(int argc, char *argv[])
{
  // some stuff

 try {
  theApp.Run();
 } catch (std::exception& exc) {
  cerr << exc.what() << std::endl;
  exit(EXIT_FAILURE);
 }
 return (EXIT_SUCCESS);
}

I don't understand why the exceptions are being catched. If they weren't, the application would simply exit and the exception would be printed.

Do you see any good reason to catch exceptions here ?


EDIT : I agree that it is good to print the exception error. However, wouldn't it be better to rethrow the exception ? I have the feeling that we are swallowing it here...

+6  A: 

Why do you say that the exception would be printed? This is not the typical behavior of the C++ runtime. At best, you can expect that its type gets printed.

In addition, this program leaves a "failure" status, whereas an exception might cause a termination-through-abort status (i.e. with a signal indicated in the exit code).

Martin v. Löwis
You are right, I mistakenly thought that the exception would be printed. It is not the case.
Barth
+3  A: 

This is a global catch block. It is common for displaying a nice and user understood message ('Internal error') instead of a cryptic exception print-out. This may be not evident from the specific code block, but it is in general a good idea.

kgiannakakis
It's only a good idea, until the first time you have to debug some mysterious exception, that is thrown from hell knows where... :)
Paulius Maruška
then can't we print it AND rethrow it ?
Barth
I guess we can, but when I'm debugging - I rarely look at what's printed - I usually look at the values in the watch window (if I need to).
Paulius Maruška
+3  A: 

Try-catch in the main function hides the exception from debugger. I would say, it isn't good.

On the other hand, customers are not expected to have debuggers, so catching exceptions is nice. So it is good.

Personally, I catch all exceptions in main function, when making a release build, and I don't do that, when building a debug configuration.

Paulius Maruška
A: 

Have a look at the C++ bible i.e. stroustrup, he has an example which is also repeated in Applied C++ programming. The reasoning is:-

int main(void) { try { // your code } catch ( /* YourPossibleExceptions i.e. barfs you expect may occur */ ) { } catch ( ... ) // unexpected errors, so you can exit gracefully { } }

Yes. But as I mentioned in my answer - it doesn't really help the debugger. If the exception is not caught - the debugger will show you the exact location in source, where the exception is thrown. So, this only makes sense in release builds.
Paulius Maruška
+7  A: 

If an exception is uncaught, then the standard does not define whether the stack is unwound. So on some platforms destructors will be called, and on others the program will terminate immediately. Catching at the top level ensures that destructors are always called.

So, if you aren't running under the debugger, it's probably wise to catch everything: (...) as well as std::exception. Then your application code can clean up with RAII even on a fatal exception. In many such cases you don't actually need to clean up, since the OS will do it for you. But for instance you might prefer to disconnect cleanly from remote services where possible, and there might be resources external to the process, such as named pipes/mutexes, that you'd prefer to destroy rather than leaking.

Rethrowing the exception in main seems to me of limited use, since you've already lost the context in which it was originally thrown. I suppose that trapping an uncaught exception in the debugger is noisier than just logging the fault to std::cerr, so rethrowing would be the smart move if there's a chance of missing the logging.

If you want the debugger to trap unexpected conditions in debug mode, which in release mode throw an exception that eventually results in an exit, then there are other ways to do that than leaving the exception uncaught so that the debugger sees it. For example, you could use assert macros. Of course, that doesn't help with unexpected and unpredictable conditions, like hardware exceptions if you're using SEH on .NET.

Steve Jessop
+2  A: 

A simple example of a situation where the stack did not unwind:
http://stackoverflow.com/questions/222175/why-destructor-is-not-called-on-exception

A list of situations where exceptions may cause the application to terminate rather than unwind the stack.
http://stackoverflow.com/questions/222175/why-destructor-is-not-called-on-exception#222358

If an exception is not caught at any level and would escape main() then the implementation is allowed to call terminate() rather that unwinding the stack (yes this caught me by surprise as well).

As a result I always catch all exceptions in main().

int main()
{
    try
    {
    }
    catch(std::exception const& e)
    {  /* LOG */
       // optimally rethrow
    }
    catch(...) // Catch anything else.
    {  /* LOG */
       // optimally rethrow
    }
}

To help with catching problems during debugging. Derive your exceptions from std::exception and then stick the break point in the constructor for std::exception.

Martin York