Day_Dreamer
Day_Dreamer

Reputation: 3373

exception with non virtual destructor c++

When we go out of catch block scope, does the exception destructor get called? (In case we don't rethrow it)

Suppose I have class A, and that its destructor is not virtual. B inherits A. Suppose some function threw object of B class as an exception, and it was caught by a catch block

catch(A& a){
...
}

If the exception destructor should be called when go out of catch scope, in this case only the base class A's destructor will be called?

Cornstalks: live trial result in calling both class destructor.

It contradicts my logic. Explain someone?

Upvotes: 14

Views: 939

Answers (4)

Ben Voigt
Ben Voigt

Reputation: 283624

Whenever the Standard says that an object is destroyed, it means that the correct most-derived destructor is invoked.

Always.

When you polymorphically delete an object without a virtual destructor, or you terminate (via delete operator or explicit destructor call) an object of incomplete type and the proper destructor is non-trivial, the Standard does not say that object is destroyed. It does not say that the base class destructor is invoked. It says you have undefined behavior.

Upvotes: 3

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385104

when we go out of catch block scope, does the exception destructor is called? (In case we don't rethrow it)

Yes:

[C++11: 15.1/4]: [..] The exception object is destroyed after either the last remaining active handler for the exception exits by any means other than rethrowing, or the last object of type std::exception_ptr (18.8.5) that refers to the exception object is destroyed, whichever is later. [..]


if the exception destructor should be called when go out of catch scope, in this case only the base class A's d'tor will be called?

No:

#include <iostream>

struct A
{
    A() { std::cout << "A()"; }
    A(const A&) { std::cout << "A(const A&)"; }
    A(A&&) { std::cout << "A(A&&)"; }
    ~A() { std::cout << "~A()"; }
};

struct B : A
{
    B() { std::cout << "B()"; }
    B(const B&) { std::cout << "B(const B&)"; }
    B(B&&) { std::cout << "B(B&&)"; }
    ~B() { std::cout << "~B()"; }
};

int main()
{
    try {
        throw B();
    }
    catch (A&) {
    }
}

// Output: A()B()~B()~A()

Upvotes: 5

Brian Bi
Brian Bi

Reputation: 119099

OK, someone already answered your first question. I'll focus on this one:

if the exception destructor should be called when go out of catch scope, in this case only the base class A's d'tor will be called?

The implementation will always destroy the exception object properly regardless of how it is caught. The implementation constructs the exception object, so it knows how to destroy it. This is not the same as when you call delete through a pointer, because in that case there is incomplete information about the complete type of the object at that point (it may have been newed somewhere else) unless a virtual destructor exists.

Were this not the case, catch (...) would never work at all.

Upvotes: 5

Cornstalks
Cornstalks

Reputation: 38218

While I'm not quoting from the standard, it seems that throwing a B and catching a A& will result in both A's and B's destructors getting called. Live demo:

#include <iostream>

struct A
{
    ~A() { std::cout << "A::~A" << std::endl; }
};

struct B : public A
{
    ~B() { std::cout << "B::~B" << std::endl; }
};

void throwit()
{
    throw B{};
}

int main()
{
    std::cout << "beginning main scope" << std::endl;

    {
        std::cout << "beginning inner scope" << std::endl;

        try
        {
            std::cout << "calling throwit()" << std::endl;
            throwit();
        }
        catch (A& a)
        {
            std::cout << "caught exception" << std::endl;
        }

        std::cout << "ending inner scope" << std::endl;
    }

    std::cout << "ending main scope" << std::endl;
}

Output:

beginning main scope
beginning inner scope
calling throwit()
caught exception
B::~B
A::~A
ending inner scope
ending main scope

As you can see, both destructors get called. The extra scope printing shows very clearly exactly when the destructors get called (at the end of the catch block).

Upvotes: 3

Related Questions