Request: catching std:: exceptions on background threads

I ran into a situation where I was getting an exception on the Audio Thread. I had written no code that threw exceptions but I was using STL objects and containers, and they throw exceptions.

I tried enabling the JUCE_CATCH_UNHANDLED_EXCEPTIONS macro, but that uses code that is defined in juce_ApplicationBase.h. My guess is that the compilation order prevents anything from that file being used in the juce_Thread.cpp file, but who knows.

With that in mind, i inserted my own exception handlers like this:

        try
        {
            run();
        }
#if JUCE_CATCH_UNHANDLED_EXCEPTIONS
        catch( const std::out_of_range& e)
        {
            DBG( "std::exception on background thread" );
            DBG( "thread: " << threadName );
            DBG( "std::out_of_range: " << e.what() );
            DBG( "file: " << __FILE__ );
            DBG( "line: " << __LINE__ );
        }
        catch (const std::exception& e)
        {
            DBG( "std::exception on background thread" );
            DBG( "thread: " << threadName );
            DBG( "std::exception: " << e.what() );
            DBG( "file: " << __FILE__ );
            DBG( "line: " << __LINE__ );
        }
        catch (...)
        {
            DBG( "unknown exception on background thread" );
            DBG( "thread: " << threadName );
            DBG( "file: " << __FILE__ );
            DBG( "line: " << __LINE__ );
        }
#else
        catch (...)
#endif
        {
            jassertfalse; // Your run() method mustn't throw any exceptions!
        }

I had to mess with the different exception types to figure out which exception was being triggered.
Turns out I had a rogue std::function<> being used that was set to nullptr. Catching const std::exception& e only gives us the base class for all exception types, so it took some time to narrow down the actual type.

This would have been easier to track down if exceptions were caught in DEBUG builds in background threads.

I always hate hacking the JUCE code, but something like this would probably help a LOT of people who are using STL containers or std::function<> on background threads and are doing a lot of late-night coding that might not be as error-proof as expected:

        try
        {
            run();
        }
#if JUCE_CATCH_UNHANDLED_EXCEPTIONS && JUCE_DEBUG
        catch (const std::exception& e)
        {
            /*
             use your debugger to see the actual exception type.
             the exception is being cast to the base class here, but
             your debugger will show the actual type.
             then you can look up the details for it here:
             https://en.cppreference.com/w/cpp/error/exception
             */
            DBG( "std::exception on background thread" );
            DBG( "thread: " << threadName );
            DBG( "std::exception: " << e.what() );
            DBG( "file: " << __FILE__ );
            DBG( "line: " << __LINE__ );
        }
        catch (...)
        {
            DBG( "unknown exception on background thread" );
            DBG( "thread: " << threadName );
            DBG( "file: " << __FILE__ );
            DBG( "line: " << __LINE__ );
        }
#else
        catch (...)
#endif
        {
            jassertfalse; // Your run() method mustn't throw any exceptions!
        }
    }

you’ll still hit the jassertfalse; too even if JUCE_CATCH_UNHANDLED_EXCEPTIONS is enabled, which is really helpful for debugging these things.