Properly terminating program. Using exceptions

There's nothing wrong with catching unrecoverable errors and shutting down your program this way. In fact, it's how exceptions should be used. However, be careful not to cross the line of using exceptions to control the flow of your program in ordinary circumstances. They should always represent an error which cannot be gracefully handled at the level the error occurred.

Calling exit() would not unwind the stack from wherever you called it. If you want to exit cleanly, what you're already doing is ideal.


It's generally considered good practice to let all exceptions propagate through to main. This is primarily because you can be sure the stack is properly unwound and all destructors are called (see this answer). I also think it's more organised to do things this way; you always known where your program will terminate (unless the program crashes). It's also facilitates more consistent error reporting (a point often neglected in exception handling; if you can't handle the exception, you should make sure your user knows exactly why). If you always start with this basic layout

int main(int argc, const char **argv)
{
    try {
         // do stuff
         return EXIT_SUCCESS;
    } catch (...) {
        std::cerr << "Error: unknown exception" << std::endl;
        return EXIT_FAILURE;
    }
}

then you won't go far wrong. You can (and should) add specific catch statements for better error reporting.

Exceptions when multithreading

There are two basic ways of executing code asynchronously in C++11 using standard library features: std::async and std::thread.

First the simple one. std::async will return a std::future which will capture and store any uncaught exceptions thrown in the given function. Calling std::future::get on the future will cause any exceptions to propagate into the calling thread.

auto fut = std::async(std::launch::async, [] () { throw std::runtime_error {"oh dear"}; });
fut.get(); // fine, throws exception

On the other hand, if an exception in a std::thread object is uncaught then std::terminate will be called:

try {
    std::thread t {[] () { throw std::runtime_error {"oh dear"};}};
    t.join();
} catch(...) {
    // only get here if std::thread constructor throws
}

One solution to this could be to pass a std::exception_ptr into the std::thread object which it can pass the exception to:

void foo(std::exception_ptr& eptr)
{
    try {
        throw std::runtime_error {"oh dear"};
    } catch (...) {
        eptr = std::current_exception();
    }
}

void bar()
{
    std::exception_ptr eptr {};

    std::thread t {foo, std::ref(eptr)};

    try {
        // do stuff
    } catch(...) {
        t.join(); // t may also have thrown
        throw;
    }
    t.join();

    if (eptr) {
        std::rethrow_exception(eptr);
    }
}

Although a better way is to use std::package_task:

void foo()
{
    throw std::runtime_error {"oh dear"};
}

void bar()
{
    std::packaged_task<void()> task {foo};
    auto fut = task.get_future();

    std::thread t {std::move(task)};
    t.join();

    auto result = fut.get(); // throws here
}

But unless you have good reason to use std::thread, prefer std::async.