Fire Lancer
Fire Lancer

Reputation: 30115

Catching all unhandled C++ exceptions?

Is there some way to catch exceptions which are otherwise unhandled (including those thrown outside the catch block)?

I'm not really concerned about all the normal cleanup stuff done with exceptions, just that I can catch it, write it to log/notify the user and exit the program, since the exceptions in these casese are generaly fatal, unrecoverable errors.

something like:

global_catch()
{
    MessageBox(NULL,L"Fatal Error", L"A fatal error has occured. Sorry for any inconvience", MB_ICONERROR);
    exit(-1);
}
global_catch(Exception *except)
{
    MessageBox(NULL,L"Fatal Error", except->ToString(), MB_ICONERROR);
    exit(-1);
}

Upvotes: 29

Views: 64084

Answers (8)

kralyk
kralyk

Reputation: 4387

Check out std::set_terminate()

Edit: Here's a full-fledged example with exception matching:

#include <iostream>
#include <exception>
#include <stdexcept>

struct FooException: std::runtime_error {
    FooException(const std::string& what): std::runtime_error(what) {}
};

int main() {
    std::set_terminate([]() {
        try {
            std::rethrow_exception(std::current_exception());
        } catch (const FooException& e) {
            std::cerr << "Unhandled FooException: " << e.what() << std::endl;
        } catch (const std::exception& e) {
            std::cerr << "Unhandled exception: " << e.what() << std::endl;
        } catch (...) {
            std::cerr << "Unhandled exception of unknown type" << std::endl;
        }

        std::abort();
    });

    throw FooException("Bad things have happened.");
    // throw std::runtime_error("Bad things have happened.");
    // throw 9001;
}

Upvotes: 27

EvilTeach
EvilTeach

Reputation: 28837

This can be used to catch unexpected exceptions.

catch (...)
{
    std::cout << "OMG! an unexpected exception has been caught" << std::endl;
}

Without a try catch block, I don't think you can catch exceptions, so structure your program so the exception thowing code is under the control of a try/catch.

Upvotes: 28

Loki Astari
Loki Astari

Reputation: 264351

This is what I always do in main()

int main()
{
    try
    {
        // Do Work
    }
    catch(std::exception const& e)
    {
         Log(e.what());
         // If you are feeling mad (not in main) you could rethrow! 
    }
    catch(...)
    {
         Log("UNKNOWN EXCEPTION");
         // If you are feeling mad (not in main) you could rethrow! 
    }
}

Upvotes: 5

oz10
oz10

Reputation: 158264

Update: This covers c++98 only.

From More Effective C++ by Meyers (pg 76), you could define a function that gets called when a function generates an exception that is not defined by its exception specification.

void convertUnexpected()
{
    // You could redefine the exception here into a known exception
    // throw UnexpectedException();

    // ... or I suppose you could log an error and exit.
}

In your application register the function:

std::set_unexpected( convertUnexpected );

Your function convertUnexpected() will get called if a function generates an exception that is not defined by its exception specification... which means this only works if you are using exception specifications. ;(

Upvotes: 7

scrutari
scrutari

Reputation: 1618

Provided that C++11 is available, this approach may be used (see example from: http://en.cppreference.com/w/cpp/error/rethrow_exception):

#include <iostream>
#include <exception>

void onterminate() {
  try {
    auto unknown = std::current_exception();
    if (unknown) {
      std::rethrow_exception(unknown);
    } else {
      std::cerr << "normal termination" << std::endl;
    }
  } catch (const std::exception& e) { // for proper `std::` exceptions
    std::cerr << "unexpected exception: " << e.what() << std::endl;
  } catch (...) { // last resort for things like `throw 1;`
    std::cerr << "unknown exception" << std::endl;
  }
}

int main () {
  std::set_terminate(onterminate); // set custom terminate handler
  // code which may throw...
  return 0;
}

This approach also allows you to customize console output for unhandled exceptions: to have something like this

unexpected exception: wrong input parameters
Aborted

instead of this:

terminate called after throwing an instance of 'std::logic_error'
  what():  wrong input parameters
Aborted

Upvotes: 6

ididak
ididak

Reputation: 5858

Use catch (...) in all of your exception barriers (not just the main thread). I suggest that you always rethrow (...) and redirect standard output/error to the log file, as you can't do meaningful RTTI on (...). OTOH, compiler like GCC will output a fairly detailed description about the unhandled exception: the type, the value of what() etc.

Upvotes: 1

paavo256
paavo256

Reputation: 181

Without any catch block, you won't catch any exceptions. You can have a catch(...) block in your main() (and its equivalent in each additional thread). In this catch block you can recover the exception details and you can do something about them, like logging and exit.

However, there are also downside about a general catch(...) block: the system finds that the exception has been handled by you, so it does not give any more help. On Unix/Linux, this help would constitute creating a CORE file, which you could load into the debugger and see the original location of the unexcepted exception. If you are handling it with catch(...) this information would be already lost.

On Windows, there are no CORE files, so I would suggest to have the catch(...) block. From that block, you would typically call a function to resurrect the actual exception:

std::string ResurrectException()
   try {
       throw;
   } catch (const std::exception& e) {
       return e.what();
   } catch (your_custom_exception_type& e) {
       return e.ToString();
   } catch(...) {
       return "Ünknown exception!";
   }
}


int main() {
   try {
       // your code here
   } catch(...) {
       std::string message = ResurrectException();
       std::cerr << "Fatal exception: " << message << "\n";
   }
}

Upvotes: 9

gbjbaanb
gbjbaanb

Reputation: 52659

You can use SetUnhandledExceptionFilter on Windows, which will catch all unhandled SEH exceptions.

Generally this will be sufficient for all your problems as IIRC all the C++ exceptions are implemented as SEH.

Upvotes: 12

Related Questions