How to add information to std :: exception using exception formatting
The Exception Exception framework is fine. You can add information to the exception received from std::exception
and boost::exception
, at the appropriate application level, as described in the documentation .
But how can you add such information if you don't control the throw site in your code, for example. std lib throws an exception eg. the map throws out_of_range?
It cannot be caught as boost :: exception because it does not derive from it:
try {
my_map.at(id);
} catch(boost::exception &e) { // NOT caught
e << errinfo_desc("id not found, map out of range");
throw;
}
It can be caught as std :: exception because out_of_range comes from std :: exception, but then no information can be added because it is not boost::exception
:
try {
my_map.at(id);
} catch(std::exception &e) {
// compile error: e << errinfo_desc("id not found, map out of range");
throw;
}
Catching std::exception
and throwing a new one boost::exception
loses the original location of the exception, which is undesirable:
try {
my_map.at(id);
} catch(std::exception &e) {
BOOST_THROW_EXCEPTION(my_exception()
<< errinfo_desc("id not found, map out of range"));
}
Is it possible to keep the original exception with its location, etc. and still be able to add more information later? How?
source to share
Personally, I use hierarchy whenever std::exception
possible. And when there aren't enough of them, I just drop my exception class out of std::exception
. There has never been a use for boost::exception
(maybe all my code is too simple for that, don't know).
But if you really want to combine both, here's a wild idea: use multiple inheritance. Code sketch (untested, more pseudocode-like):
// two personalities in one exception object
class MyException: public std::exception, public boost::exception {
explicit MyException(const std::exception& stdex) { ... }
... other ctors as needed...
... other stuff ...
};
...
try {
my_map.at(id);
} catch (const std::exception& stdex) {
MyException myex(stdex); // gets SOME of the std::exception information
myex << errinfo_desc("id not found, map out of range"); // boost::exception goodies
throw myex;
}
Obvious caveat: slice issues when initializing MyException objects with std :: exception reference. And the usual MI problems. You were warned :-)
source to share
You can do this by catching both cases: boost::exception
andstd::exception
try {
my_map.at(id);
} catch(boost::exception &e) {
// If already a boost exception, catch here and add information
e << errinfo_desc("id not found, map out of range");
throw;
} catch(std::exception &) {
// Otherwise, catch here and convert to a boost exception
try { boost::rethrow_exception( boost::current_exception() ); }
catch( boost::exception& e ) {
e << errinfo_desc("id not found, map out of range");
throw;
}
}
If I find it painful to write a lot of code, I asked if there is a cleaner way to do this: Adding error_info to std :: exception
source to share