Are destructors required to be virtual when implementing curiously recurring template pattern (CRTP)? And if not, what is the proper non-virtual implementation?
I'll provide an example to hopefully make things easier:
template<typename T>
class Base
{
public:
virtual ~Base()
{
// Should this be virtual? Non-virtual?
std::cout << "Base::~Base()\n";
}
};
class Derived : public Base<Derived>
{
public:
~Derived() override
{
std::cout << "Derived::~Derived()\n";
}
};
int main()
{
Base<Derived>* b = new Derived;
delete b;
}
Result:
Derived::~Derived()
Base::~Base()
(Live Sample Here)
EDIT: Updated the example to use runtime polymorphism so that the virtual destructor is required for proper cleanup.
A CRTP base class is no different from any other base class in this sense. You will need a virtual destructor only if you are going to delete an object of type Derived via a pointer to Base<Derived>. Otherwise, a virtual destructor is not required.
Base<Derived>* b = new Derived;
delete b; // Base<Derived>::~Base<Derived> must be virtual
In the example you showed, a virtual destructor is not needed. A virtual destructor is just needed when you may need to call it using a pointer to the base class, the same as an overriden function must be virtual in this case. And in the case of a CRTP class like you showed, there is rarely a need to delete a Base<T> instead of T itself.
int main()
{
Derived *a = new Derived();
// we have the right type anyway, so dont actually need a virtual anything (even normal virtual methods)
delete a;
Derived *a = new Dervied();
Base<Derived> *b = a;
// We are now deleting via a parent class, so this needs a virtual destructor.
// This is pretty uncommon with a simple CRTP however.
delete b;
}
If you're going to call delete on a pointer of a base class that's pointing to a derived object then you need a virtual destructor, that's all there is to it. CRTP or no CRTP.
Related
In the code below, why is the ~Derived() destructor called automatically?
#include<iostream>
using namespace std;
class Base
{
public:
virtual ~Base()
{
cout << "Calling ~Base()" << endl;
}
};
class Derived: public Base
{
private:
int* m_pnArray;
public:
Derived(int nLength)
{
m_pnArray = new int[nLength];
}
virtual ~Derived()
{
cout << "Calling ~Derived()" << endl;
delete[] m_pnArray;
}
};
int main()
{
Derived *pDerived = new Derived(5);
Base *pBase = pDerived;
delete pBase;
return 0;
}
Because your base class destructor is virtual
virtual ~Base();
the call to delete on a pointer to a base class results in virtual call to destructor and as any virtual call is dispatched to matching function in derived class. It is not only good, but necessary: otherwise the behavior is undefined.
This is crucial for a derived classes which destructor is not an empty function. Non-virtual call would otherwise result in calling base class destructor, derived resources being leaked, etc.
When you have at least one virtual function in a class, then the compiler creates a single table for the class listing the member function pointers. Consider:
struct Base
{
virtual ~Base() { };
int n_;
};
In pseudo-code you can imagine the compiler adding:
void* Base::__virtual_dispatch_table[] = { (void*)&Base::~Base };
Then, when you have an actual object of type Base it will have an extra hidden data member that points to the Base::__virtual_dispatch_table (the "VDT"):
Variable definition Memory layout
------------------- -------------
Base myBase; int n_;
void** __p_vdt = Base::__virtual_dispatch_table;
Now, if you have a Base* p and delete p;, the compiler says "hey - it's virtual - I won't hardcode a call to Base::~Base, instead I'll generate code that does something like this pseudo-code:
void (Base::*p_destructor) = p->__p_vdt[0]
*p_destructor(p); // "p" will provide the "this" value while the destructor runs
Why would you want to do all that? Because when you come along with a Derived object...
class Derived: public Base
{
private:
int* m_pnArray;
...
...the compiler can create a separate virtual dispatch table...
void* Derived::__virtual_dispatch_table[] = { (void*)&Derived::~Derived };
...andd lay out the Derived object's memory like this:
Variable definition Memory layout
------------------- -------------
Derived derived; int n_;
void** __p_vdt = Derived::__virtual_dispatch_table;
int* m_pnArray;
Notice that the __p_vdt is in the same relative location within the object layout, but now points to the Derived class's virtual dispatch table?
Now, if you create a Base* to derived, the exact same code needed to call the destructor for a Base object, which - in case you've lost track - was...
void (Base::*p_destructor) = p->__p_vdt[0]
*p_destructor(p); // "p" will provide the "this" value while the destructor runs
...can be run but will end up using the Derived object's __p_vdt value of Derived::__virtual_dispatch_table, and finding the Derived class's destructor.
Because it allows you to treat any Base object (which may in fact be a Derived) as an object that you can delete.
In this case, if delete pBase didn't call the Derived destructor, the data held by m_pnArray would never get deleted, i.e. a "memory leak" would occur.
When you call
delete pBase;
It looks at the virtual function table of pBase to find the appropriate destructor to begin unwinding at, and it finds Derived::~Derived and then works its way down the stack.
I have a class hierarchy that's three levels deep, like this:
class A {
public:
virtual ~A() {}
}
class B : public A {
public:
virtual ~B() {}
void foo(E *e) {
e->remove(this);
}
}
class C : public B {
public:
~C() {}
}
class E {
public:
void remove(A *a) {
delete a;
}
}
Ok so what I am wondering is what happens when I call foo() on an object of C. Is it going to remove the entire object or only the B and A part of the object, and leave the C part still in memory?
Is it going to remove the entire object or only the B and A part of the object, and leave the C part still in memory?
No. It will "do the right thing" (that is, delete the most derived subobject, run all its destructors etc.) provided A (that is, the static type of the pointee of the pointer you delete) has a virtual destructor (and if class A has a virtual destructor, all its descendants have it, too). This holds for multiple inheritance, too.
Thanks to the virtual destructor in A the code would work correctly destroy the entire instance of C.
delete will always release the memory for the whole object pointed to.
This doesn't apply to called destructors however: It will try to call the destructor of the static type of the object to delete.
In a polymorphistic scenario, this is often not what you want. Consider this:
struct Base { };
struct Derived : Base
{
int* i;
Derived() : i(new int) { }
~Derived() { delete i; }
}
void bad()
{
Base* b = new Derived;
delete b;
}
bad() causes a memory leak, because Deriveds destructor will never be called. This is because the static type of b is Base*, thus Base::~Base will be called. There is no destructor defined in Base, so the default implementation provided by the compiler executes, which does nothing in this particular example.
This however does not apply to your example: You made the root class' destructor virtual, so all derived classes' destructors will be executed as part of the destructor call.
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?
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.
Suppose I have this code
class Base{
public:
int getVal();
private:
int a, b;
};
class Derived::public Base{
public:
void printVal();
};
int main(){
Base *b = new Derived();
delete b;
}
I know a virtual destructor would delete things properly, but is it bad to delete with base pointer (when there is no virtual destructor) even if there are no virtual functions and no data members in the derived class? What will happen if this is done?
Is it bad to delete with base pointer (when there is no virtual destructor) even if there are no virtual functions and no data members in the derived class?
Yes.
The behavior is undefined regardless the contents of the derived class.
What will happen if this is done?
Anything could happen.
For primitive-type data, your example will most likely work in practice. As a matter of fact, incurring a vtable could actually hinder performance (so there may be some legitimate use here), but it is technically undefined, per 5.3-5.4:
If the static type of the operand [of
the delete operator] is different from
its dynamic type, the static type
shall be a base class of the operand's
dynamic type and the static type shall
have a virtual destructor or the
behaviour is undefined.
It really all depends on the "heapness" of the data in your class, and as there are no heap-allocated members (in your case), you should be fine, but it's definitely a code smell.
The virtual desctructor in the derived class is needed in order to properly call the derived destructor (polymorphism), when the derived object is created through a pointer to the base class.
High Integrity CPP Rule 3.3.2 Write a 'virtual' destructor for base classes. (QACPP 2116)
Justification: If an object will ever be destroyed through a pointer to its base class, then that base class should have a virtual destructor. If the base class destructor is not virtual, only the destructor for the base class will be invoked. In most cases, destructors should be virtual, because maintenance or reuse may add derived classes that require a virtual destructor.
class Base {};
class Derived : public Base { public: ~Derived() {} };
void foo() {
Derived* d = new Derived; delete d; // correctly calls derived destructor
}
void boo() {
Derived* d = new Derived; Base* b = d; delete b; // problem! does not call derived destructor!
}
Do I need virtual destructor when I am using boost::ublas matrix ?
By the way, my class is a template class.
Do you mean you have this?
template <typename Whatever>
struct my_class
{
// ...
boost::ublas::matrix m;
};
There's nothing here that dictates you have a virtual destructor.
You want a virtual destructor when you intend on having users publically derive from your class. So that question should be "Users will publically derive from my class, do I need a virtual destructor?". Yes, you do.
The reason is that doing this leads to undefined behavior:
struct base {}; // no virtual destructor
struct derived : base {};
base* b = new derived;
// undefined behavior, dynamic type does not match static type,
// and the base class does not have a virtual destructor
delete b;
This does not:
struct base { virtual ~base(){} }; // virtual destructor
struct derived : base {};
base* b = new derived;
// well-defined behavior, dynamic type does not match static type,
// but the base class has a virtual destructor
delete b;
Note that it has nothing to do with what members there are in the base class. You always need a virtual destructor if users will be deleting derived classes through a pointer to a base class.
I would recommend you get a book so you know what it does, because it sounds like you just throw things around and hope it works, which isn't a very good approach.