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:
std::rethrow_if_nested
std::rethrow_with_nested
std::rethrow_exception
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:
print_backtrace
function to capture exceptions with catch (...)
to capture absolutely all?std::rethrow_exception
is needed and I don't know when either. As a rule of thumb, exception handling is extremely cheap when you don't throw an exception. It costs nothing on some implementations. All the cost is incurred when you throw an exception: that is, “normal code” is faster than code using error-return codes and tests.
Exceptions are preferred in modern C++ for the following reasons: An exception forces calling code to recognize an error condition and handle it. Unhandled exceptions stop program execution. An exception jumps to the point in the call stack that can handle the error.
Explanation: C++ uses catch block to handle any exceptions that occur during run-time of the program.
Explanation: As the func() is throwing a const char* string but we the catch block is not catching any const char* exception i.e. exception thrown is not handled therefore the program results into Aborted(core dumped).
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) {
// ...
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