Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I make a call to what() on std::exception_ptr

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.

like image 966
Ram Avatar asked Jan 09 '13 10:01

Ram


Video Answer


1 Answers

// 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

like image 91
anton_rh Avatar answered Oct 05 '22 21:10

anton_rh