In g++
and clang++
(in Linux at least) the following typical message is shown after an exception is thrown and not catch (uncaught exception):
terminate called after throwing an instance of 'std::runtime_error'
what(): Bye
For example in:
#include<stdexcept>
int main(){
throw std::runtime_error("Bye");
}
How do I customize the error message while still having full access to the thrown exception?
The documentation (http://www.cplusplus.com/reference/exception/set_unexpected/) mentions set_unexpected
(and set_terminate
) but I don't know how the unexpected_handle
has actual access to the exception being thrown, for example to call e.what()
or something else.
Note: The reason behind this is that I want to customize the message for a more complicated exception class hierarchy that has more information than simple what()
, and I want to display it if such type exception is thrown (but if a simple std::exception&
is thrown the default is the same as the typical.
Note2: According to the two suggestions so far, "customize uncaught exceptions by catching the exceptions." Will look like what follows in the code. I was wondering if there is a way to do the same without adding a try-catch
block to all main()
code that I write.
#include<stdexcept>
int main() try{
....
}catch(std::exception& e){
std::clog << "terminate called after throwing an instance of '" << typeid(e) << "'\n"
<< " what(): " << e.what() << '\n'
<< "otherinfo, like current time\n";
}catch(alternative_exception& e){
std::clog << "terminate called after throwing an instance of '" << typeid(e) << "'\n"
<< " what(): " << e.what() << '\n'
<< " where(): " << e.where() << '\n'
<< " how(): " << e.how() << '\n'
<< "othermember(): " << e.othermember() << '\n';
}
Apart from actually catching the exceptions you care about, std::set_terminate()
and std::current_exception()
(C++11) ought to be enough to do something interesting.
The hook for customizing the handling of uncaught exceptions is catching the exceptions.
Based on @JonPurdy (accepted) answer, I experimented with this code that seems to work, at least with gcc 4.7.2 and clang 3.2 in Linux. I have no idea how robust or portable it is (comments welcomed), I tried not to make assumptions about the default terminate handler:
#include<stdexcept>
#include<iostream>
#include<typeinfo> // for typeid
// a special exception, can be an abstract class, here it is concrete class to make the example shorter.
struct debug_exception : std::runtime_error{
std::string where_;
debug_exception(std::string what, std::string where) : std::runtime_error(what), where_(where){}
virtual const char* where() const{return where_.c_str();}
};
std::terminate_handler my_default_terminate;
void my_verbose_terminate_handler(){
try{
throw;
}catch(debug_exception& e){
std::cerr << "my_verbose_terminate_handler called after throwing an instance of "
<< typeid(e).name() << std::endl; // or demangled
std::cerr << " what(): " << e.what() << std::endl;
std::cerr << " where(): " << e.where() << std::endl;
}catch(...){
my_default_terminate(); // probably __gnu_cxx::__verbose_terminate_handler();
}
}
std::terminate_handler my_improve_terminate(){
my_default_terminate = std::set_terminate(my_verbose_terminate_handler);
return my_default_terminate;
}
int main(){
my_improve_terminate();
// throw 2; // says the default "terminate called after throwing an instance of 'int'"
// throw std::runtime_error("bye"); // says the default "terminate called ... what(): bye"
throw debug_exception("Bye", __PRETTY_FUNCTION__); // says my_verbose_terminate_handler called ... what(): Bye, where(): int main()"
}
Now I am experimenting with wrapping all the code in a class
and call my_improve_terminate()
before main
so when including a certain file it becomes the new default.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With