I've noticed that there are a few more interesting declarations in <exception>
in C++11. Can anybody shed any light on what they mean and how to use them?
The ones I'm wondering about are:
::std::nested_exception
::std::throw_with_nested
::std::rethrow_if_nested
Additionally, while they seem self-explanatory, it might be nice to know how these worked:
::std::exception_ptr
::std::make_exception_ptr
::std::current_exception
::std::rethrow_exception
Some high level code will generically just catch std::exception
and print the what()
. You want to squeeze as much information as possible to this generic mechanism, yet without losing any information. Consider an implementation of some archive library:
archive::archive(const char* filename)
{
ifstream file(filename);
file.exceptions(ios_base::badbit);
open_archive(file); // throws ios_base::failure, or some other low-level exception.
}
The information available to the archive is not recorded (e.g. filename). Besides you would like to distinguish exceptions that came from the archive class from other exceptions.
archive::archive(const char* filename)
{
try {
ifstream file(filename);
file.exceptions(ios_base::badbit);
open_archive(file); // throws ios_base::failure, or some other low-level exception.
} catch(const std::exception& e) {
throw archive_exception("Can't open archive", filename, e.what());
}
}
Now we added higher-level semantic information that archive
class knows, but we also lost the information about the original cause of problem (the type of e
). nested_exception
is meant to solve this problem:
archive::archive(const char* filename)
{
try {
ifstream file(filename);
file.exceptions(ios_base::badbit);
open_archive(file); // throws ios_base::failure, or some other low-level exception.
} catch(...) {
throw_with_nested(archive_exception("Can't open archive", filename));
}
}
All the available information is recorded. We can now generically retrieve it in the catch site:
void print_exception_info(const std::exception& e)
{
cerr << e.what() << "\n";
try {
rethrow_if_nested(e);
} catch(const std::exception& ne) {
print_exception_info(ne);
} catch(...) { }
}
int main() {
try {
run();
} catch(const std::exception& e) {
print_exception_info(e);
}
}
The output will be more descriptive than before. It will describe the problem starting from the high-level to the low-level:
Can't open archive "my_archive.bin"
Access is denied.
Or perhaps:
Can't open archive "my_archive.bin"
Record 'aabb' not found.
The functions working with exception_ptr
are designed to transfer exceptions between threads, or more generally, store an exception for later use. How they work depends on the implementation. The intention was that exception_ptr
will be a shared pointer to the exception object. However when this pointer is created, when throwing the exception or when trying to get an exception_ptr
to it, is subject to the implementation. The implementation is still free to copy the exception when you call current_exception()
.
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