When writing exception handlers (e.g. around calls to database or network related code), you often end up with the same set of catch clauses at each call site. Suppose you end up with the following code:
try {
//...
} catch (std::runtime_error& e) {
std::cout << "Runtime error: " << e.what() << std::endl;
} catch (...) {
std::cout << "Unknown exception!" << std::endl;
}
You have this piece of code repeated dozens of times, which is not really a Good Thing(tm)... A little C++ trick can help you avoid those repetitions: (1) factor the common code into a single function or method that rethrows the active exception and catches it immediately, and (2) catch all exceptions at the call sites and call this handler!
#include <iostream>
#include <stdexcept>
void exception_handler() {
try {
throw; //rethrow the current exception
} catch (std::runtime_error& e) {
std::cout << "Runtime error: " << e.what() << std::endl;
} catch (...) {
std::cout << "Unknown exception!" << std::endl;
}
}
int main() {
try {
throw std::runtime_error("unable to comply...");
} catch (...) { exception_handler(); }
try {
throw 1;
} catch (...) { exception_handler(); }
return 0;
}
You must be careful to not call
exception_handler() outside a
catch clause: the
trow statement calls
terminate() if there is no active exception to rethrow!
You may wonder if one could use the
std::uncaught_exception() function to protect against this.
void exception_handler() {
try {
if (!std::uncaught_exception()) {
return; // Nothing to rethrow...
}
throw; //rethrow the current exception
} ...
}
But this does not work:
uncaught_exception() "returns
true after completing evaluation of the object to be thrown until completing the initialization of the exception-declaration in the matching handler", as the standard says. And when
exception_handler is entered, this is generally from the
catch clause, and the exception has thus been caught... Your handler would now simply swallow all the exceptions!...
Actually,
uncaught_exception is pretty much useless...