4
votes

I am trying to understand better the throw-catch mechanism when dealing with inheritance.

The problem I an trying to solve is the case of what will happens if while constructing the derived class the base class which is constructed first throws an exception.

#include <stdexcept>
#include <iostream>

class Base
{
    public:
    Base()
    {
        throw  std::runtime_error("test");
    }
};


class Derived : public Base
{
    public:
    Derived() try : Base()
    {

    }
    catch (std::runtime_error& e)
    {
        std::cout <<  "Base throws an exception : " << e.what() << std::endl;
    }    
};


int main ()
{
   Derived temp;
   return (0);
}

After running my compiled code (g++ std=11) I get the following message:

Base throws an exception : test

terminate called after throwing an instance of 'std::runtime_error'

what(): test

Aborted (core dumped

My exception thrown by Base is caught by the try-catch of Derived constructor but for some reason the thrown exception does not stop there, why is that, and how to solve this?

And regardless I am open to suggestions if there is a better way to handle exception that may be thrown by base class when the derived is constructed.

2

2 Answers

3
votes

It is a fundamental C++ core principle that an object is fully constructed only after the object's constructor returns. When execution enters the class's constructor, the class itself is not constructed yet. Only its class members are (and any base classes, too). Only when the constructor returns, only then the object is fully constructed, and you have a fully-cooked object to play with.

Therefore, a thrown exception in the constructor means that the object was not constructed. Full stop. End of story. That's all she wrote. No exceptions to this rule (pun intended).

Now, what does this mean, when you catch an exception that's thrown from the base class's constructor? Well, you can do that but it does not change the fact that an exception got thrown and the base class was not constructed. Which means that the derived class cannot be constructed. You can't expect the execution to reach the end of the exception handler, and then return to the parent, as if the class has been fully constructed without errors.

That is not just going to happen. You can't, somehow, end up with a base class not getting constructed, but the derived class getting constructed. C++ does not work this way.

When you catch an exception from the base class, you have only two options:

1) Your exception handler can rethrow its own exception, after it does whatever it wants to do.

2) Otherwise, C++ will rethrow the exception for you, if the exception handler returns without throwing its own exception.

1
votes

Yes, that is the correct behavior. You have a try/catch block that captures the exceptions from the base class and initializer list. According to the standard this exception is automatically rethrown from the catch block. The same is true if you capture the exception in the destructor making try/catch a body of the destructor.