6
votes

My large application has this structure:

int main()
{
    try {
        ...
    } catch (std::exception& e) {
        std::cout << "Fatal error: " << e.what() << (some more data) << std::endl;
        return 1;
    }
}

Deep inside the call stack, various objects check their internal state, throwing std::runtime_exception if they detect something bad. The all-inclusive exception handler catches it, prints some moderately useful info and terminates the program.

However, when I am debugging under MS Visual Studio, I could benefit from not having any exception handler: Visual Studio has its own, very useful, handler, which stops my application at the place where the exception is thrown, so I can examine what went wrong.

How can I do the catching of my exceptions conditionally?

I tried the following:

    try {
        ...
    } catch (std::exception& e) {
        if (IsDebuggerPresent())
            throw;
        else
            std::cout << "Fatal error: " << e.what() << (some more data) << std::endl;
    }

This gave a weird result: Visual Studio caught the exception that was rethrown and showed me the stack trace at the point where the exception was thrown. However, all objects in my application were apparently destructed, and I couldn't see e.g. local or member variables.

I could make the exception handler conditional on a compilation flag:

#ifdef NDEBUG
    try {
#endif
        ...
#ifdef NDEBUG
    } catch (std::exception& e) {
        std::cout << "Fatal error: " << e.what() << (some more data) << std::endl;
    }
#endif

but this is inconvenient because I have to recompile everything if I want to debug it.

So, how can I make my exception handling conditional (depending on a command-line argument, for example)?

2
Try Debug -> Exceptions and tick the "Break on throw" box for the exception(s) you want to catch. - CompuChip
A better method would be to conditionally throw an exception that your handlers simply can't catch (through a level of indirection), leaving it up to the debugger to snatch 'em. - Filip Roséen - refp
If @CompuChip's method works for you, it is definitely the better of these two. - TonyK

2 Answers

2
votes

So, how can I make my exception handling conditional (depending on a command-line argument, for example)?

By writing the code for it :o]

Consider this original code:

int main()
{
    try {
        run_the_application(); // this part different than your example
    } catch (std::exception& e) {
        std::cout << "Fatal error: " << e.what() << (some more data) << std::endl;
        return 1;
    }
}

New code:

template<typename F>
int fast_run(F functor) { functor(); return EXIT_SUCCESS; }

template<typename F>
int safe_run(F functor)
{
    try {
        functor();
    } catch (std::exception& e) {
        std::cout << "Fatal error: " << e.what() << (some more data) << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

template<typename F>
int run(const std::vector<std::string>& args, F functor)
{
    using namespace std;
    if(end(args) != find(begin(args), end(args), "/d"))
        return fast_run(functor);
    else
        return safe_run(functor);
}

int main(int argc, char** argv)
{
    const std::vector<std::string> args{ argv, argv + argc };
    return run(args, run_the_application);
}
1
votes

As suggested by CompuChip, Visual Studio can break execution when throwing an exception, not only when catching an uncaught one!

To enable this (in Visual Studio 2012):

  1. In the menu, go Debug -> Exceptions
  2. In the opened window, tick the "Thrown" box for all C++ exceptions (ticking just std::exception is not enough - I don't know why)
  3. Run your program