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?
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 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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With