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?

+3


source to share


2 answers


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 :-)

0


source


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

0


source







All Articles