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_nestedAdditionally, 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_exceptionSome 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