std::exception_ptr
Channel
C++Weekly episode request
Topics
std::exception_ptr seems to have no practical use at all. All you can do is get an exception_ptr using std::currenct_exception() and then rethrow it. That would seem to be how it should be used. You rethrow, and immediately catch a specific exception type, like std::exception&.
Why was the class designed this way? Because, C++ unlike many other languages, does not mandate that all exception classes inherit from a common base class. In fact, it is possible to throw an int!
Where is it used and where can it be used?
Some libraries use it to define exception handlers that get called when an exception is thrown in user provided callbacks.
It could also be used to standardize exception logging code in a project:
// Call in a catch(...) block.
void logException() {
auto ep = std::current_exception();
if (ep == nullptr) {
std::cout << "Not called from an exception handler\n";
} else {
try {
std::rethrow_exception(ep);
} catch (const std::exception& exc) {
std::cout << "Exception thrown: " << exc.what() << "\ntype: " << typeid(exc).name() << '\n;
} catch (...) {
std::cout << "Unknown exception\n";
}
}
}
Length
5-10 minutes should be sufficient.
It's designed that way because C++ already has detailed rules for taking an ordered list of (possibly unrelated) exception types and selecting one - the try/catch mechanism. Providing any other form of access would be creating a whole separate set of rules. The opaque nature of std::exception_ptr allows for code that doesn't care or know about all the relevant exception types to just pass it along to someone who does, and refactoring doesn't need to change how the exception is inspected since the existing try/catch will work as expected.
And yes, one great use is for smuggling exceptions past noexcept boundaries like C APIs without having to use a lippincott or lose valuable information that needs to be shown to the user for diagnosing the actual cause of the error. Some other uses include:
- Storing an exception in a
std::futureto re-throw it when you call.get() - Storing a list of exceptions that occurred while performing operations that all needed to at least be attempted before error handling could take place
- Combining the above two, storing a list of exceptions that occurred from parallelized background tasks (e.g. a bunch of file operations and some failed)