C++11 exception design. Idioms and best practices changed?

I am wondering if, since C++11, where passing exceptions between threads was added and nested exceptions were added, idioms changed for exception capturing, in general.

Now we have:

  1. std::rethrow_if_nested
  2. std::rethrow_with_nested
  3. std::rethrow_exception
  4. std::current_exception

Nested exceptions are supposed to be used to not lose context for exceptions.

So now you can do something like this:

void open_file(std::string const & file_name) {
   try {
      std::ifstream file;
      file.exceptions(ios::failbit | ios::badbit);
      file.open(file_name);
   }
   catch (...) {
      std::rethrow_with_nested(std::logic_error("File " + file_name + 
      " could not be open"));
   }
}

You can get the backtrace like this, if I'm not wrong:

void print_backtrace(std::exception const & e, int depth = 0) {
   std::cerr << std::string(depth, ' ') << e.what() << std::endl;
   try {
      std::rethrow_if_nested(e);
   }
   catch (std::exception const & ex) {
      print_backtrace(ex, ++depth);
   }
}

So if you use print_backtrace with open_file it should give you the std::logic_error + the ios_base::failure in the output.

My questions are:

  1. Is this idiom the "correct" way of handling exceptions in c++11, given that I want to capture all exceptions without losing context?
  2. Is there a way in the print_backtrace function to capture exceptions with catch (...) to capture absolutely all?
  3. I don't know why std::rethrow_exception is needed and I don't know when either.

Answers


1. I don't know that I'd call it an idiom. If by 'the "correct"' you mean something similar to how std::vector is the 'correct' container to use by default, I don't think there really is a particular "correct" way of handling errors. This is a correct way in that it's well defined behavior.

2. First you have to call print_backtrace() in a context that's not limited to certain exceptions, which means you have to call it in a catch(...) block:

    try {
      run();
    } catch(...) {
      print_backtrace();
    }

But then you don't have an exception of a known type to pass along to the function. Instead you have to write the function to access the exception differently; by throwing that exception and catching it internally (since this is the only mechanism by which you can bind a variable of a known type to an arbitrary exception).

void print_backtrace(int depth = 0) {
  try {
    throw;
  }

  // this block shows how to handle exceptions of some known type
  // You can have your own types instead of std::exception
  catch (const std::exception & e) {
    std::cerr << std::string(depth, ' ') << e.what() << std::endl;
    try {
      std::rethrow_if_nested(e);
    }
    catch (...) {
      print_backtrace(++depth);
    }
  }

  // Not all nesting exceptions will be of a known type, but if they use the
  // mixin type std::nested_exception, then we can at least handle them enough to
  // get the nested exception:

  catch (const std::nested_exception & ne) {
    std::cerr << std::string(depth, ' ') << "Unknown nesting exception\n";

    try {
      ne.rethrow_nested();
    }
    catch (...) {
      print_backtrace(++depth);
    }
  }

  // Exception nesting works through inheritance, which means that if you
  // can't inherit from the type, then you can't 'mixin' std::nesting exception.
  // If you try something like std::throw_with_nested( int{10} ); Then you'll
  // hit this catch block when printing the backtrace.

  catch (...) {
    std::cerr << std::string(depth, ' ') << "Unknown exception\n";
  }
}

3. std::rethrow_exception is used with std::exception_ptr, which is a type that can be used to transport an arbitrary exception. The only way to get at that exception is to use the normal exception handling machinery to catch the exception, which means you have to be able to throw that exception. That's what rethrow_exception does. This can be used to transport an arbitrary exception from one thread to another (as std::future does), or to hold an arbitrary exception as a member (as std::nested_exception does), or to pass an arbitrary exception as a parameter to a function which will try to print some description of the exception.

void print_backtrace(std::exception_ptr e) {
  try {
    std::rethrow_exception(e);
  }

  catch (const std::exception & e) {
    // ...

Need Your Help

How to parse malformed HTML in python, using standard libraries

python html dom parsing html-parsing

There are so many html and xml libraries built into python, that it's hard to believe there's no support for real-world HTML parsing.

How to write integration tests with spring-cloud-netflix and feign

java netflix-eureka spring-cloud-netflix wiremock feign

I use Spring-Cloud-Netflix for communication between micro services. Let's say I have two services, Foo and Bar, and Foo consumes one of Bar's REST endpoints. I use an interface annotated with @