I'm trying to print nested exceptions using the following example code from cppreference.com:
void print_exception(const std::exception& e, int level = 0)
{
std::cerr << std::string(level, ' ') << "exception: " << e.what() << '\n';
try {
std::rethrow_if_nested(e);
} catch(const std::exception& e) {
print_exception(e, level+1);
} catch(...) {}
}
However, I get an abort if the innermost exception is a std::nested_exception rather than a std::exception (IE I throw a std::nested_exception, catch it, and then apply print_exception).
This is a minimal example:
int main() {
try {
std::throw_with_nested( std::runtime_error("foobar") );
} catch(const std::exception& e1) {
std::cerr << e1.what() << std::endl;
try {
std::rethrow_if_nested(e1);
} catch( const std::exception& e2 ) {
std::cerr << e2.what() << std::endl;
} catch( ... ) {
}
} catch ( ... ) {
}
}
It aborts:
foobar
terminate called after throwing an instance of 'std::_Nested_exception<std::runtime_error>'
what(): foobar
Aborted (core dumped)
The documentation for std::throw_with_nested states that
The default constructor of the nested_exception base class calls
std::current_exception, capturing the currently handled exception
object, if any, in a std::exception_ptr
so I would expect e1 to derive from std::nested_exception but have no nested_ptr. Why does std::rethrow_if_nested not handle this? What is the best approach for me to handle this case?
You may write something like:
// Similar to rethrow_if_nested
// but does nothing instead of calling std::terminate
// when std::nested_exception is nullptr.
template <typename E>
std::enable_if_t<!std::is_polymorphic<E>::value>
my_rethrow_if_nested(const E&) {}
template <typename E>
std::enable_if_t<std::is_polymorphic<E>::value>
my_rethrow_if_nested(const E& e)
{
const auto* p = dynamic_cast<const std::nested_exception*>(std::addressof(e));
if (p && p->nested_ptr()) {
p->rethrow_nested();
}
}
Demo
Related
// Example program
#include <iostream>
#include <string>
#include <stdexcept>
void log(const std::exception& e) {
try {
throw e;
}
catch (const std::logic_error& e1) {
std::cout << "logic_error: " << e1.what() << std::endl; // How to get logic_error back once caught?
}
catch (const std::exception& e1) {
std::cout << "exception: " << e1.what() << std::endl;
}
}
int main()
{
try {
throw std::logic_error("sth wrong");
}
catch (const std::exception& e) {
log(e);
}
}
I don't want to add more catch clauses is because I want to have a central place to log detailed exception message, it could be very different across different exceptions.
Is there a way to narrow down the std::exception to derived exception in the catch clause?
You can rethrow the original exception in your log method to preserve its original state. This way everything should work as you would expect it.
Modified log method looks like this:
void log(const std::exception& e) {
try {
throw;
}
catch (const std::logic_error& e1) {
std::cout << "logic_error: " << e1.what() << std::endl;
}
catch (const std::exception& e1) {
std::cout << "exception: " << e1.what() << std::endl;
}
}
See throw expression for more details on how throw e and throw differs in this example.
std::exception::what() is virtual. So you don't need to get back the original type to write the logs. You just have to ensure that what() is redefined for your custom exceptions that inherits std::exception.
This may become:
void log(const std::exception & e)
{
std::cout << e.what() << std::endl;
}
You might use std::rethrow_exception:
void log(std::exception_ptr eptr) {
try {
if (eptr) {
std::rethrow_exception(eptr);
}
}
catch (const std::logic_error& e1) {
std::cout << "logic_error: " << e1.what() << std::endl;
}
catch (const std::exception& e1) {
std::cout << "exception: " << e1.what() << std::endl;
}
}
int main()
{
try {
throw std::logic_error("sth wrong");
}
catch (const std::exception&) { // or even catch (...)
log(std::current_exception());
}
}
You don't have to use only base exceptions provided by the standard library, you can make your own exception hierarchy with the methods you need.
#include <exception>
#include <string>
#include <iostream>
class MyBaseException: public std::exception
{
public:
virtual std::string output() const = 0;
/* Define methods you need here */
};
class MySpecificException : public MyBaseException
{
public:
const char* what() const noexcept override {return "error"; }
std::string output() const override { return "Specific debug output that I want"; }
};
int main(){
try{
throw MySpecificException{};
}catch(const MyBaseException& e){
std::cout << e.output() << '\n';
}catch(const std::exception& e) {
std::cout << e.what() << '\n';
}
}
You can use run time type information to get the type of the execption:
#include <iostream>
#include <string>
#include <stdexcept>
#include <typeinfo>
#if defined(__clang__) || defined(__GNUC__)
#include <cxxabi.h>
#endif
std::string getTypename(const std::exception& e)
{
#if defined(__clang__) || defined(__GNUC__)
// .name() returns a mangled name on gcc and clang
int status;
return abi::__cxa_demangle(typeid( e ).name(), 0, 0, &status);
#else
// visual studio returns a human readable name
return typeid( e ).name();
#endif
}
void log(const std::exception& e) {
std::cout << getTypename( e ) << ": " << e.what() << std::endl;
}
int main()
{
try {
throw std::logic_error("sth wrong");
}
catch (const std::exception& e) {
log(e);
}
}
The getTypename() method may not work on all platforms and you might need to adjust it to your needs. You might want to use boost::core::demangle rather than calling the gcc demangle API directly.
I'm new to C++ (coming from C) and writing a class B that is a member of another class A.
The member B will throw an exception if the parent tries to access data that does not exist from B's container (I throw an invalid_argument exception). The member B has an object that can be thought of like an STL container, so it will be for this example.
My question is: if I catch the original invalid_parameter exception in A, is it considered good C++ practice to re-throw the same exception (I'd re-throw the original error, but I do some logging in it, so the what() is different), or can I just throw std::exception. My code now has many
try { A.calls_b_exception } catch (std::invalid_argument& ie) {...} catch (std::exception& e) {...}
blocks and I was wondering if I could reduce them to
try { A.calls_b_exception } catch (std::exception& e) {...}
and still be following good C++ paradigms.
Example code that is similar to my situation:
class B
{
std::vector<int> stuff;
int get_value(int index)
{
if (index >= stuff.size()) {
stringstream err;
err << "--> invalid index " << index << " for stuff";
throw std::invalid_argument(err.str());
}
}
}
class A
{
B b;
// Assume there are methods to add a bunch of stuff to B
int get_value(int index)
{
try {
b.get_value();
} catch (std::invalid_argument& ie) {
stringstream err;
err << ie.what() << "\n\t--> A::get_value(" << index << ")";
// should I throw the same exception here or is this considered good C++ etiquette?
throw std::exception(err.str());
} catch (std::exception& e) {
throw; // something I was not anticipating handling happened
}
}
}
int main
{
A a;
// Assume more stuff to add to A
try {
a.get_value(-1);
}
catch (std::exception& e) {
stringstream err;
err << "--> invalid index " << index << " for main";
throw std::exception(err.str());exception here?
}
}
You cannot instantiate std::exception(std::string), so my initial approach will not work.
Thanks to those of you who took time to read through my question and help me out.
I have many different exceptions defined in exception.thrift:
exception InvalidArgumentsError {
1: string parameter
}
/**
* Server has an problem while executing a function.
* Execution aborted.
*/
exception ServerInternalError {
1: string parameter
}
/**
* Server answer is empty.
*/
exception NoDataError {
1: string parameter
}
This is how i catch them in my C++ code:
catch (InvalidArgumentsError & ex) {
std::cout << ex.parameter;
}
catch (ServerInternalError & ex) {
std::cout << ex.parameter;
}
catch (NoDataError & ex) {
std::cout << ex.parameter;
}
catch (apache::thrift::TException& ex) {
std::cout << "TException:\n" << ex.what();
} catch (const std::exception& ex) {
std::cout << ex.what();
return;
}
I want to write something like this and catch all my exceptions:
catch (SomeBasicException& ex) {
std::cout << ex.what();
}
catch (const std::exception& ex) {
std::cout << ex.what();
}
If I just catch TException and call what() I just get 'Default TException' message because derived classed do not override virtual what() method.
Generated code by thrift compiler:
class InvalidArgumentsError : public ::apache::thrift::TException {
public:
static const char* ascii_fingerprint; //..
static const uint8_t binary_fingerprint[16]; //..
InvalidArgumentsError() : parameter() {
}
virtual ~InvalidArgumentsError() throw() {}
std::string parameter;
_InvalidArgumentsError__isset __isset;
void __set_parameter(const std::string& val) {
parameter = val;
}
//...
};
If you want to stop the repetitive typing then this might be a solution.
When you want to catch your exceptions, you write something like this:
catch (...) {
handle_exception(print_message);
}
print_message is a function that does whatever you want with the message (in this case, print it):
void print_message(char const* const msg)
{
std::cout << msg;
}
handle_exception is written like this:
template<typename F>
void handle_exception(F handler)
try {
throw;
}
catch (InvalidArgumentsError const& ex) {
handler(ex.parameter.c_str());
}
catch (ServerInternalError const& ex) {
handler(ex.parameter.c_str());
}
catch (NoDataError const& ex) {
handler(ex.parameter.c_str());
}
catch (apache::thrift::TException const& ex) {
handler(ex.what());
}
catch (std::exception const& ex) {
handler(ex.what());
}
To handle a new exception you add it to the catch clauses of the handle_exception function.
Albeit this does not really answer the question literally (#Simple did a good job at this already) I would like to propose a somewhat different approach.
Given the code posted above:
exception InvalidArgumentsError {
1: string parameter
}
exception ServerInternalError {
1: string parameter
}
exception NoDataError {
1: string parameter
}
If we look at the pattern, we could - without loosing any information and without producing greater incompatibilities - change it into this:
enum ErrorCode
Success = 0, // always good to have some null value
ServerInternalError = 1
NoData = 2
InvalidArguments = 3
// add more errors here
}
exception MyServiceException {
1: string parameter
2: ErrorCode code
}
I'm fully aware that this might not fit your particular problem (e.g. if there are more exception data than just a 1:parameter). But there may be cases where that approach could be worth considering. I've used it myself quite a few times.
I'm integrating boost::exception into existing code. Some of the code now uses BOOST_THROW_EXCEPTION, but some might still throw standard std::exception.
I want to add error_info at an intermediary catch site. According to the docs, if the exception is a boost::exception, I can just do this:
try {
do_something()
}
catch( boost::exception & e ) {
e << boost::errinfo_file_name(file_name);
throw;
}
But that will only add the info to the boost exceptions. I want to add it to the std::exception as well. What's the cleanest way to do that? Here's one way, but it results in some code duplication:
try {
do_something()
}
catch( boost::exception & e ) {
e << boost::errinfo_file_name(file_name);
throw;
}
catch( std::exception & e ) {
throw enable_error_info(e) << boost::errinfo_file_name(file_name);
}
Is there a method that's equivalent to "give me the current exception as a boost exception, or create a boost exception out of it if it isn't one"?
EDIT: boost::enable_error_info() kinda does that but returns a copy of the original exception, which slices off the boost::exception part of the exception I'm catching. Case in point:
int main()
{
try {
try {
BOOST_THROW_EXCEPTION( std::runtime_error( "foo" ) );
}
catch( std::exception & e ) {
std::cerr << e.what() << std::endl; // "foo"
if( const char* const* function = boost::get_error_info<boost::throw_function>(e) ) std::cerr << *function << std::endl; // "int main()"
throw boost::enable_error_info(e) << boost::errinfo_file_name("bar");
}
}
catch( std::exception & e ) {
std::cerr << e.what() << std::endl; // "std::exception"
if( const char* const* function = boost::get_error_info<boost::throw_function>(e) ) std::cerr << *function << std::endl; // NOTHING
}
return 0;
}
EDIT: I tried using boost::current_exception(), and it slices things off too. Basically, any attempt to copy an exception will loose some of the data because of the slicing caused by multiple inheritance. Same reason as why the docs say you should always rethrow using throw instead of throw e. So I really don't want to incur any copying unless it's necessary.
Ideally, I'd like to write the following, where current_exception_as_boost_exception() returns a reference to the current exception if it is already a boost::exception, otherwise returns the result of calling boost::enable_error_info on it.
try {
do_something()
}
catch( std::exception & e ) {
throw current_exception_as_boost_exception() << boost::errinfo_file_name(file_name);
}
Is that what boost::enable_current_exception is for? It's really unclear what its purpose is, and it's not used in any of the tutorials.
Here is a solution that does what I want. But if feels like I'm reinventing something here. Isn't there a built-in way to achieve the same thing?
struct rethrow
{
rethrow()
{
try{ throw; }
// Already a boost::exception
catch( boost::exception& ) {}
// Something else. Make it a boost::exception
catch( ... ) { ptr = boost::current_exception(); }
}
template<class T>
rethrow const& operator<<( const T& t ) const
{
try
{
re();
}
catch( boost::exception& e )
{
e << t;
}
return *this;
}
~rethrow()
{
re();
}
private:
void re() const
{
if( !ptr ) throw;
else boost::rethrow_exception( ptr );
}
boost::exception_ptr ptr;
};
int main()
{
try {
try {
throw std::runtime_error( "foo" ); // or BOOST_THROW_EXCEPTION( std::runtime_error( "foo" ) );
}
catch( std::exception & e ) {
rethrow() << boost::errinfo_file_name("bar");
}
}
catch( std::exception & e ) {
std::cerr << __LINE__ << ": caught " << e.what() << std::endl; // "caught foo"
if( const char* const* function = boost::get_error_info<boost::throw_function>(e) ) std::cerr << __LINE__ << ": throw from " << *function << std::endl; // "throw from int main()" (when using BOOST_THROW_EXCEPTION)
if( std::string const* fileName = boost::get_error_info<boost::errinfo_file_name>(e) ) std::cerr << __LINE__ << ": trying to open " << *fileName << std::endl; // "trying to open bar"
}
return 0;
}
This is the code I have.
try
{
// code throws potentially unknown exception
}
catch (...)
{
std::exception_ptr eptr = std::current_exception();
// then what ?
}
Ideally, I would like to get the string associated to the exception if it is a std::exception.
// then what ?
here is what:
#include <exception>
#include <stdexcept>
#include <iostream>
#include <string>
std::string what(const std::exception_ptr &eptr = std::current_exception())
{
if (!eptr) { throw std::bad_exception(); }
try { std::rethrow_exception(eptr); }
catch (const std::exception &e) { return e.what() ; }
catch (const std::string &e) { return e ; }
catch (const char *e) { return e ; }
catch (...) { return "who knows"; }
}
int main()
{
try { throw std::runtime_error("it's success!"); }
catch (...) { std::cerr << "Here is WHAT happened: " << what() << std::endl; }
try { throw 42; } catch (...) { std::cerr << "and now what: " << what() << std::endl; }
}
what it prints:
Here is WHAT happened: it's success!
and now what: who knows
http://coliru.stacked-crooked.com/a/1851d2ab9faa3a24
so this allows to get what in the catch-all clause.
but what if exception is nested??? here is what:
std::string what(const std::exception_ptr &eptr = std::current_exception());
template <typename T>
std::string nested_what(const T &e)
{
try { std::rethrow_if_nested(e); }
catch (...) { return " (" + what(std::current_exception()) + ")"; }
return {};
}
std::string what(const std::exception_ptr &eptr)
{
if (!eptr) { throw std::bad_exception(); }
try { std::rethrow_exception(eptr); }
catch (const std::exception &e) { return e.what() + nested_what(e); }
catch (const std::string &e) { return e ; }
catch (const char *e) { return e ; }
catch (...) { return "who knows"; }
}
using example from here:
#include <fstream>
...
// sample function that catches an exception and wraps it in a nested exception
void open_file(const std::string& s)
{
try {
std::ifstream file(s);
file.exceptions(std::ios_base::failbit);
} catch(...) {
std::throw_with_nested( std::runtime_error("Couldn't open " + s) );
}
}
// sample function that catches an exception and wraps it in a nested exception
void run()
{
try {
open_file("nonexistent.file");
} catch(...) {
std::throw_with_nested( std::runtime_error("run() failed") );
}
}
int main()
{
try { throw std::runtime_error("success!"); }
catch (...) { std::cerr << "Here is WHAT happened: \"" << what() << '\"' << std::endl; }
try { run(); }
catch (...) { std::cerr << "what happened for run: \"" << what() << '\"' << std::endl; }
}
what is printed:
Here is WHAT happened: "success!"
what happened for run: "run() failed (Couldn't open nonexistent.file (basic_ios::clear))"
http://coliru.stacked-crooked.com/a/901a0c19297f02b5
but what if recursion too deep? what if stackoverflow? optimized what:
#include <typeinfo>
template <typename T>
std::exception_ptr get_nested(const T &e)
{
try
{
auto &nested = dynamic_cast<const std::nested_exception&>(e);
return nested.nested_ptr();
}
catch (const std::bad_cast &)
{ return nullptr; }
}
#if 0 // alternative get_nested
std::exception_ptr get_nested()
{
try { throw ; }
catch (const std::nested_exception &e) { return e.nested_ptr(); }
catch (...) { return nullptr ; }
}
#endif
std::string what(std::exception_ptr eptr = std::current_exception())
{
if (!eptr) { throw std::bad_exception(); }
std::string whaaat;
std::size_t num_nested = 0;
next:
{
try
{
std::exception_ptr yeptr;
std::swap(eptr, yeptr);
std::rethrow_exception(yeptr);
}
catch (const std::exception &e) { whaaat += e.what() ; eptr = get_nested(e); }
catch (const std::string &e) { whaaat += e ; }
catch (const char *e) { whaaat += e ; }
catch (...) { whaaat += "who knows"; }
if (eptr) { whaaat += " ("; num_nested++; goto next; }
}
whaaat += std::string(num_nested, ')');
return whaaat;
}
the same whats:
Here is WHAT happened: "success!"
here is what: "run() failed (Couldn't open nonexistent.file (basic_ios::clear))"
http://coliru.stacked-crooked.com/a/32ec5af5b1d43453
UPD
The similar functionality can be implemented in C++03 by using a trick that allows to rethrow current exception outside of catch block: https://stackoverflow.com/a/3641809/5447906
try
{
std::rethrow_exception(eptr);
}
catch (const std::exception& e)
{
std::cerr << e.what() << std::endl;
}
http://en.cppreference.com/w/cpp/error/exception_ptr
Using std::current_exception seems a bit over the top in your case, since you don't seem to want to store or copy the std::exception_ptr for later processing (which is its only intent, it doesn't help with gaining additional information about an unknown exception in any way). If you just want to treat the case of a std::exception, what about the simple:
try
{
// code throws potentially unknown exception
}
catch (const std::exception &e)
{
std::cerr << e.what() << '\n'; // or whatever
}
catch (...)
{
// well ok, still unknown what to do now,
// but a std::exception_ptr doesn't help the situation either.
std::cerr << "unknown exception\n";
}
Not the best solution in my opinion but seems to work.
try
{
// code throws potentially unknown exception
}
catch (const std::exception& e)
{
std::cerr << e.what() << std::endl;
}
catch (...)
{
std::exception_ptr eptr = std::current_exception();
// then what ?
LogUnknownException();
}
Thanks to ForEveR for the initial solution but I am not sure if I want to throw again within the catch block.