views:

167

answers:

8

Hello!

Does C++ offer a way to 'show' something visual if an unhandled exception occurs?

What I want to do is to make something like assert(unhandled exception.msg()) if it actually happens (like in the following sample):

void foo() {
   throw std::exception("Message!");
}

int main() {
 foo();
}

I expect this kind of code not to terminate immediately (because exception was unhandled), rather show custom assertion message (Message! actually).

Is that possible?

+1  A: 

If I'm reading your question correctly, you're asking if you can overload throw (changing its default behavior) so it does something user-defined. No, you can't.

Edit: since you're insistent :), here's a bad idea™:

#include <iostream>
#include <stdlib.h>
#include <windows.h>

void monkey() {
   throw std::exception("poop!");
}

LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *lpTopLevelExceptionFilter) {
    std::cout << "poop was thrown!" << std::endl;
    return EXCEPTION_EXECUTE_HANDLER;
  }

int main() {
    SetUnhandledExceptionFilter(&MyUnhandledExceptionFilter);
    monkey();
    return 1;
}

Again, this is a very bad idea, and it's obviously platform-dependent, but it works.

David Titarenco
@David Not `throw` actually. I want to change default behaviour when an unhandled exception situation occurs.
HardCoder1986
So basically, when you `throw` an unhandled exception :-P
David Titarenco
+4  A: 

Microsoft Visual C++ allows you to hook unhandled C++ exceptions like this. This is standard STL behaviour.

You set a handler via a call to set_terminate. It's recommended that your handler do not very much work, and then terminate the program, but I don't see why you could not signal something via an assert - though you don't have access to the exception that caused the problem.

Steve Townsend
The terminate handler shouldn't assert. It might `printf` (or better, just `write(2)` to `STDERR_FILENO`), though, and call the terminate_handler it replaced. Also, see Logan's answer and discussion for why the exception should still be accessible at that point.
Potatoswatter
@Potatoswatter - is your statement applicable in all circumstances - in other words would it be possible to assert, but not recommended? Thanks.
Steve Townsend
@Steve: It's always possible to assert, but any of the handler functions are recommended to tail-call the previously installed handler.
Potatoswatter
@Potatoswatter - thanks
Steve Townsend
+2  A: 

If you are using Windows, a good library for handling unhandled exceptions and crashes is CrashRpt. If you want to do it manually you can also use the following I wrote in this answer.

Brian R. Bondy
+1 for more expansive answer to a narrow q
Steve Townsend
+3  A: 

I think you would benefit from a catch-all statement as follows:

int main() {
 try {
   foo();
 catch (...) {
   // Do something with the unhandled exception.
 }
}
Christopher Hunt
TokenMacGuy
A good point indeed.
Christopher Hunt
On Windows you have to be a little careful with the (...) catching structured exception thrown internally (ex. access violations). It may be dangerous to continue execution under conditions like these.
seand
It's probably not possible to continue execution with this method regardless of what exception occured. This catches the exception only after the stack has been completely unrolled all the way up to `main()`. At that point, you may as well `exec(argv[0])`.
TokenMacGuy
+1  A: 

Yes, its possible. Here you go:

#include <iostream>
#include <exception>

void foo() 
{
   throw std::exception("Message!");
}

int main() 
{
  try
  {
    foo();
  }
  catch (std::exception& e)
  {
    std::cout << "Got exception: " << e.what() << std::endl;
  }

  return 0;
}
karlphillip
A: 

The c++ standard is the terminate handler - as other have said

If you are after better traceablility for throws then this is what we do

We have a macro Throw that logs the file name and line number and message and then throws. It takes a printf style varargs message.

Throw(proj::FooException, "Fingle %s unable to process bar %d", fingle.c_str(), barNo);

I get a nice log message

Throw FooException from nargle.cpp:42 Fingle barf is unable to process bar 99
pm100
There are two issues with this. First, it adds additional processing to exceptions that are caught. This isn't much of a problem because if it happens enough that the overhead (or noise in the log) is a problem, you shouldn't be using exceptions for that case anyway. The second issue is a more practical concern. When exception conditions happen, the extra processing might fail as well. Preallocating buffers for error messages can help, but ultimately you need to make sure to protect against failure during error reporting.
Ben Voigt
since its me throwing (not the runtime) I am not in catastrophic (no memory, no stack , dead heap) mode, so the handler works. If not then I am dead anyway. I use this technique in very large commercial enterprise products (100s kloc) - with no problem. I can tune the logging level to supress overhead
pm100
+3  A: 

There's no way specified by the standard to actually display the message of the uncaught exception. However, on many platforms, it is possible anyway. On Windows, you can use SetUnhandledExceptionFilter and pull out the C++ exception information. With g++ (appropriate versions of anyway), the terminate handler can access the uncaught exception with code like:

   void terminate_handler()
   {
       try { throw; }
       catch(const std::exception& e) { log(e.what()); }
       catch(...) {}
   }

and indeed g++'s default terminate handler does something similar to this. You can set the terminate handler with set_terminate.

IN short, no there's no generic C++ way, but there are ways depending on your platform.

Logan Capaldo
I like this. The standard might not specifically require it, but it does say an exception is only deactivated when the block catching it exits. Since that can't happen before terminate, this should be portable or at least forward-compatible to everything eventually. The same trick should work with `unexpected`, and that would allow a diagnostic for illegal throw-on-unwind.
Potatoswatter
Also, it can catch exceptions thrown from global constructors and destructors, which a catch block in `main` can't.
Potatoswatter
@Potatoswatter I've seen at least one setup where this trick doesn't really work, I don't claim to be knowledgeable enough about the standard (and the other things we were doing with exception handling) to say one way or the other, but I know it works on Linux with a modernish gcc.
Logan Capaldo
I also found that there were situations that you could get into terminate w/o there being an exception, so I used `abi::__cxa_current_exception_type` to find out if there was one before trying to rethrow it, and obviously that's a non-portable gccism.
Logan Capaldo
@Logan: No, I wouldn't expect it to be portable as a practical matter in the current timeframe. Well, if you also set an unexpected handler, then the rethrow just translates the `terminate` into an `unexpected`. You can add some logic to continue along the appropriate handler chain (i.e. `unexpected` calls the replaced `terminate` handler) and the rest of the program is none the wiser, right?
Potatoswatter
A: 

If you're really interested in what happened to cause your program to fail, you might benefit from examining the process image in a post-mortem debugger. The precise technique varies a bit from OS to OS, but the basic train is to first enable core dumping, and compile your program with debug symbols on. Once the program crashes, the operating system will copy its memory to disk, and you can then examine the state of the program at the time it crashed.

TokenMacGuy