Exception class copy constructor
Asked Answered
B

1

6

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.

Bavaria answered 15/6, 2018 at 23:2 Comment(0)
C
5

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.

Colleencollege answered 15/6, 2018 at 23:9 Comment(1)
The reason why I was assuming it must call std::terminate is because of the standard C++14 N4296 - §18.8.2 that says "Each standard library class T that derives from class exception shall have a publicly accessible copy constructor and a publicly accessible copy assignment operator that do not exit with an exception.". But based on your excellent explanation then now I know the reason is not to prevent terminating, but something else. Do you know what's the reason? How come they didn't include the standard the constructor as well? thanks in advance! @NicolBolasBavaria

© 2022 - 2024 — McMap. All rights reserved.