Reputation: 986
I'm testing how throwing when doing stack unwinding calls std::terminate
by having the copy constructor of the class that is used to throw, throwing.
Per C++14 N4296 - §15.1.3:
Throwing an exception copy-initializes (8.5, 12.8) a temporary object, called the exception object. The temporary is an lvalue and is used to initialize the variable declared in the matching handler (15.3).
class X
{
public:
X() = default;
X(const X&)
{
throw std::runtime_error{"X copy constructor"};
}
};
int main()
{
try
{
throw X{};
}
catch(const std::exception& e)
{
std::cout << e.what() << std::endl; // this line gets executed, does not terminate
}
catch(const X& other)
{
std::cout << "X exception" << std::endl;
}
}
How come the above code doesn't call std::terminate
? It is my understanding of the above code that the throw X{}
inside the try
, starts the stack winding and then the copy constructor gets called to call the handler, but the copy constructor throws as well. As a note if change the copy constructor's throw expression for throw X{}
then it terminates.
Upvotes: 6
Views: 880
Reputation: 473222
Until the exception object has been initialized, no exception has been thrown yet. And thus, the system has not started doing exception handling.
Since the copy is throwing, and that's what initializes the exception object, the only throw
that successfully executes is the one in the copy constructor.
As a note if change the copy constructor's throw expression for throw X{} then it terminates.
That's effectively a stack overflow due to infinite recursion. Each attempt to construct an exception object provokes another exception and another attempt to construct an exception object.
Upvotes: 5