Can a base-class (constructor) detect if a derived constructor threw an exception?

100 Views Asked by At

I wonder if a base class can detect (and react upon) exceptions thrown in a derived constructor.

In this somewhat artificial example, I would like to avoid the warning when the Derived instance cannot be constructed, because it cannot be closed by the user. I could wrap the derived constructor in a try/catch block, but I would have to require that for each derived constructor. Ideally, I would like to implement this in the base class itself. I have found how to catch a base-class constructor exception in the derived class (How to catch a base class constructor's exception in C++?), but I would like something like the inverse of that.

#include <iostream>

struct Base {
    void close() {
        closed = true;
    }
    
    ~Base() {
        if (!closed) std::cout << "Warning: I should be closed!" << std::endl;
    }

private:
    bool closed = false;
};

struct Derived : public Base {
    Derived() : Base() {
        throw 0;
    }
};

int main() {
    // Issues warning
    Base not_closed;

    // Issues no warning    
    Base().close();
    
    // How can I prevent a warning here?
    try {
        Derived derived;
    } catch (...) {
    }
}

Update: one alternative could be to skip calling ~Base, but I understand that is not possible.

1

There are 1 best solutions below

0
463035818_is_not_an_ai On

Can a base-class (constructor) detect if a derived constructor threw an exception?

No.

The base class constructor is executed before the derived class constructor. By the time you throw the exception, the base class subobject is already constructed.

Assuming you want to stay with inheritance you can turn the logic around to avoid the warning:

#include <iostream>

struct Base {
    void close() { closed = true; }
    void open() { closed = false; }
    ~Base() {
        if (!closed) std::cout << "Warning: I should be closed!" << std::endl;
    }
private:
    bool closed = true;
};

struct Derived : public Base {
    Derived() : Base() {        
        throw 0;
        Base::open();
    }
};

int main() {
    try {
        Derived derived;
    } catch (...) {}
}

Live Demo

The Base initializes closed = true and when constructing the Derived does not throw, it calls open().

If you can give up on inheritance, make Base a member of Derived to be in control of order of initialization.