Reputation: 28300
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)?
Upvotes: 8
Views: 1842
Reputation: 21778
This is something far from great but you can define command line parameter in CMake (assuming you use it):
-DCATCH_ALL=true
Then, in CMakelists.txt, you can propagate this to C++ macro:
if (CATCH_ALL)
message("Some exceptions with not be caught")
add_compile_definitions(CATCH_ALL)
else ()
message("Trying to catch more exceptions to provide better diagnostics")
endif ()
And finally, in the code:
#ifdef CATCH_ALL
try {
#endif
a = big_problematic_algorithm(problematic_parameter);
#ifdef CATCH_ALL
} catch (const std::exception &err) {
LOGF(WARN, "Crashed for the parameter %s: %s", problematic_parameter.c_str(), err.what());
}
#endif
It is rather clumsy but OK if not used too often, only somewhere at very high level (handling a complete web request, user action, file to process or the like). It allows to provide better diagnostic logs if the crash happens not while running in IDE, also to recover if you throw this exception yourself so know how.
It is possible to configure IDE to set the CMake parameter. When building on the integration server or from the command line, this is just not done activating additional handling of exceptions.
Upvotes: 1
Reputation: 28300
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):
std::exception
is not enough - I don't know why)Upvotes: 1
Reputation: 27385
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);
}
Upvotes: 2