Exception x Exception
In my previous post, we demystified std::forward. In this one, we'll explore what happens when you encounter another exception while handling one in its catch block. We'll also examine the requirements that this second exception should satisfy.
Let's start by observing what occurs when we throw another exception while already handling one:
In this scenario, the inner exception is destructed, and the catch block in the main will have no record of it. Consequently, cleaning up in the catch block of run2 is incomplete, and you lose your only opportunity to do so.
Here's the output from the previous program:
C++11 introduced std::nested_exception, a construct designed to assist in such situations. With throw_with_nested, we can nest the current_exception() in our Outer exception. Later in the main function, we can check for the Inner exception with rethrow_if_nested(). Let's see how the previous code changes to reflect this:
And the output:
Here you can observe that the Inner exception is destructed in the main function, and the Outer exception is moved once. Also, take note of the type of the Outer exception.
throw_with_nested creates a compile-time type derived from both std::nested_exception and Outer. On the other hand, rethrow_if_nested checks if it can dynamically cast to std::nested_exception. If successful, it calls the rethrow_nested member function of std::nested_exception to access the Inner exception.
Now that we understand how it all works, let's take a closer look at what happens if Outer doesn't provide a copy or move constructor. Below is the implementation of Inner and Outer.
Recommended by LinkedIn
We will proceed by removing the copy and move constructor from Outer.
And it will complain with a compilation error.
If we make our Outer class final, we won't encounter any compilation errors. The Outer exception will still be thrown. However, the caveat is that there will be no trace of the Inner exception. It's as if we never used the throw_with_nested.
Here is the output of the code with the only change being making Outer final.
If we examine the implementation of throw_with_nested, everything becomes clear:
You can observe that in this context, Outer (referred to as Up) should be copy or move constructible. Additionally, it should be a class type that is not final and is not a descendant of nested_exception itself.
I hope you find this useful. The code is available at my cpplab repository under the exception directory.
#C++ #Cpp #cpp #cplusplus #cplusplusprogramming #cplusplusdeveloper #exceptionhandling #exception #exceptions #cpp11 #nested_exception #cpplab #exception_in_exception