Search code examples
c++memory-leaksderivedvirtual-destructor

effect of both base and derived virtual destructors


I've had some second thoughts on multiple virtual destructors, esp. after reading reading http://blogs.msdn.com/b/oldnewthing/archive/2004/05/07/127826.aspx .

Suppose I have

class Base
{
    public:
        Base();
        virtual ~Base();

    private:
        Logger* _logger;
};

//and

class Derived : public Base{
    public:
        Derived();
        virtual ~Derived();

    private:
        Logger* _logger;
};

in the cpp files, in each destructor I am deleting the respective _logger pointers

Base::~Base(){  //base.cpp
    delete _logger;
}
Derived::~Derived(){ //derived.cpp
    delete _logger;
}

will this work as I intended, without memory leaks?


Solution

  • First off, if you make the base class destructor virtual, all derived classes will automatically get a virtual destructor if you declare them as virtual or not. This is generally true for matching signatures: if a base class has a virtual function with the same signature as a function in a derived class, the function in the derived class is an override and is virtual (although in C++ 2011 you can prevent further overriding using the final keyword in which case another override would create an error).

    That said, destructors are special: when you make a destructor virtual it will still be called even if there is another overriding destructor! The only impact of a destructor being virtual is what happens if you delete an object using a pointer to a base class when the object actually happens to be of a derived type: If the destructor isn't virtual you get undefined behavior while the Right Thing happens if the destructor is virtual. For example:

    class not_a_base {};
    class bad_idea: public not_a_base {};
    
    class a_base { public: virtual ~a_base() {} };
    class ok: public a_base {};
    
    int main() {
        a_base* ab = new ok;
        delete ab; // <---- all is good here!
    
        not_a_base* nab = new bad_idea;
        delete nab; // <---- results in undefined behavior
    }
    

    The reason destructors are not virtual by default is simply that this would mean that object size is always increased by a word size which is unacceptable in general.