Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 213
icy Avatar asked Nov 17 '12 00:11

icy


People also ask

What is the use of base class destructor virtual?

Making base class destructor virtual guarantees that the object of derived class is destructed properly, i.e., both base class and derived class destructors are called. For example, Constructing base Constructing derived Destructing derived Destructing base

What is virtual destructor?

What is Virtual destructor? What is its use? - If the destructor in the base class is not made virtual, then an object that might have been declared of type base class and instance of child class would simply call the base class destructor without calling the derived class destructor.

What happens if destructors are not marked as virtual in C++?

As noted in the top example, if the base class destructor isn’t marked as virtual, then the program is at risk for leaking memory if a programmer later deletes a base class pointer that is pointing to a derived object. One way to avoid this is to mark all your destructors as virtual.

How to fix “deleting a derived class with a non-virtual destructor”?

Deleting a derived class object using a pointer of base class type that has a non-virtual destructor results in undefined behavior. To correct this situation, the base class should be defined with a virtual destructor. For example, following program results in undefined behavior.


2 Answers

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.

like image 156
Dietmar Kühl Avatar answered Oct 07 '22 12:10

Dietmar Kühl


Base::_logger is a different variable then Derived::_logger. So you should delete Derived::_logger in Derived's dctor, or else you leak memory.

Note that this has nothing to with it being private. Consider this example program:

#include <iostream>

class A {
public:
    bool foo;
};

class B: public A {
public:
    bool foo;
};

int main()
{
    B b;
    std::cout << &b.B::foo << ' ' << &b.A::foo << '\n';
}

The addresses are different. That means they're different variables, even though they have the same name. This is possible since each class introduces its own namespace, so the names don't really clash. The first is A::foo, the other one B::foo.

Since your destructors are virtual, both will get called, and the correct _logger will be deleted in both of them.

like image 33
Nikos C. Avatar answered Oct 07 '22 12:10

Nikos C.