No virtual functions, but still need virtual destructor? - c++

I wrote a base and derived class that had no virtual functions. The use of virtual is typically the guide I see for when to use a virtual destructor.
However, while my classes have no virtual functions I am using the classes in a polymorphic way when I pass them around. Therefore, class Base should implement a virtual destructor?
class Base;
class Derived;
main()
{
base& baseVar = derived();
foo(baseVar);
}

There is no polymorphism because you call (will call) non-virtual functions using the referemce. That is in your example you simply call (will call) functions of the base class.
Moreover this statement
base& baseVar = derived();
should not be compiled because you bind a temporary object with a non-const reference.
There must be
const base& baseVar = derived();
As for the destructor in your example then there is no need to have a virtual destructor. Becasue you defined a reference to a temporary object of the derived class. In this case for the temporary object will be called its own destructor. That is at first the destructor of the base class will be called (from the destructor of the derived class) and then the body of the destructor of the derived class will be executed.
The vertual destructor would be need if you would allocate a derived memory in the heap and assign the address of the allocated memory to a pointer of the base class. And when you would call operator delete for this pointer then if you have no virtual destructor then the only destructor of the base class would be called.
For example
class Base;
class Derived;
main()
{
base* baseVar = new derived();
delete baseVar; // base shall have a virtual destructor
}

You should use a virtual destructor if your program will ever find itself in the position where it will be deleting an instance of a derived class through a base class pointer to ensure the correct destructor is called.
See this question for more detail When to use virtual destructors?

Related

Virtual destructor in polymorphic classes

I understand that whenever you have a polymorphic base class, the base class should define a virtual destructor. So that when a base-class pointer to a derived-class object is deleted, it will call the destructor of the derived class first. Correct me if i am wrong here.
also, if the base-class destructor were to be non-virtual, it would be undefined behavior to delete a baseclass pointer to a derived object. Correct me if i am wrong aswell.
so my question is: Why is it exactly, that when the base-class destructor is non-virtual, the object will not be destroyed correctly?
i am assuming this is because virtual functions have some kind of table that is memorized and consulted whenever a virtual function is called. And the compiler knows that when an object is supposed to be deleted, it should call the derived destructor first.
is my assumption correct?
If at the point where you delete the object the static type of the variable is the bas type, than the destructor of the base type will be called, but the destructor of the sub class won't be called (as it is not virtual).
As a result the resources allocated by the base class will be freed, but the resources allocated by the sub class won't.
Thus the object won't be destructed correctly.
You are correct about that table: it is called a virtual method table or "vtable". But the result of the destructor being non-virtual is not that the destructors are not called in the correct order, but that the destructor(s) of the sub class(es) are not called at all!
Consider
struct Base {
void f() { printf("Base::f"); }
};
struct Derived : Base {
void f() { printf("Derived::f"); }
};
Base* p = new Derived;
p->f();
This prints Base::f, because Base::f is not virtual. Now do the same with destructors:
struct Base {
~Base() { printf("Base::~Base"); }
};
struct Derived : Base {
~Derived() { printf("Derived::~Derived"); }
};
Base* p = new Derived;
p->~Base();
This prints Base::~Base. Now if we make the destructor virtual, then, as with any other virtual function, the final overrider in the dynamic type of the object is called. A destructor overrides a virtual destructor in a base class (even though its "name" is different):
struct Base {
virtual ~Base() { printf("Base::~Base"); }
};
struct Derived : Base {
~Derived() override { printf("Derived::~Derived"); }
};
Base* p = new Derived;
p->~Base();
The call p->~Base() actually invokes Derived::~Derived(). Since this is a destructor, after its body finishes executing, it automatically invokes destructors of bases and members. So the output is
Derived::~Derived
Base::~Base
Now, a delete-expression is in general equivalent to a destructor call followed by a call to a memory deallocation function. In this particular case, the expression
delete p;
is equivalent to
p->~Base();
::operator delete(p);
So if the destructor is virtual, this does the right thing: it calls Derived::~Derived first, which then automatically calls Base::~Base when it's done. If the destructor isn't virtual, the likely result is that only Base::~Base is invoked.

Pure virtual call in destructor of most derived class

I know you shouldn't call any virtual function in the ctor or dtor of the base class, but what about from that of the most derived class? Should be fine right? E.g.
class base {
...
virtual void free() = 0;
};
class child : public base {
...
free() {/* free memory */}
~child() {free();}
};
Well, you can do it, but the dynamic type of *this inside child::~child() is child, and not anything more derived. So when you have a further derived class class foo : child which overrides free(), then the overridden function will not be called.
There's nothing wrong with calling a virtual function from a constructor or destructor, base class or otherwise. But you have to know what it does: the dynamic type is the class being constructed or destroyed, so it won't call an override in a class derived from the one that's being constructed or destroyed. In particular, if the function is pure virtual, you won't get an override, and the behavior is undefined. So a good rule is "don't call pure virtual functions from constructors or destructors. In your example, class::free is not pure virtual, so there's no problem calling it.

Is a derived class destructor definition required if base class destructor is virtual?

I am trying the following example:
class base // base class
{
public:
std::list<base*> values;
base(){}
void initialize(base *b) {
values.push_front(b);
}
virtual ~base()
{
values.clear();
cout<<"base called"<<endl;
}
};
class derived : public base // derived class
{
public:
~derived(){
cout<<"derived called"<<endl;
}
};
int main()
{
derived *d = new derived;
base *b = new base;
b->initialize(static_cast<base *>(d)); /* filling list */
delete b;
return 0;
}
Q.1) Why does destructor of derived class not get called, as in base class destructor I am performing values.clear()?
Q.2) Is derived class destructor definition required if base class destructor is virtual?
Q1. Because you're not deleting an object of type derived. You only do delete b;, which deletes a base. You should also call delete d;.
Also, you should specify what object is responsible for memory management. Your design is prone to error. You're better off using a smart pointer to prevent ambiguity. Also, to behave as you expect it, the destructor should be:
virtual ~base()
{
for ( int i = 0 ; i < values.size() ; i++ )
delete values[i];
values.clear();
cout<<"base called"<<endl;
}
Of course, with this approach, it would be undefined behavior calling delete d; in your main.
Q2. No, the definition is not required.
Why does destructor of derived class is not getting called, as in base class destructor I am performing values.clear();
values.clear() removes all the pointers from this list. It does not delete the objects being pointed to; that would be extremely dangerous, since the list has no way of knowing whether it's responsible for their lifetime, or whether they are just being used to refer to objects managed elsewhere.
If you want the list to own the objects, then you must either delete them yourself when removing them, or store smart pointers such as std::unique_ptr<base>. If your compiler doesn't support the new smart pointers, then you might find Boost's Pointer Container library useful.
Does derived class destructor definition is required. If base class destructor is virtual.
It's only needed if there is something in the derived class that needs cleaning up. There's no need to define an empty one if there's nothing for it to do.
You don't actually delete d, so of course the destructor is not being called. Either make d statically allocated (derived d instead of derived *d = new derived) or call delete d.
If you don't declare the destructor in the derived class a default one will be created. The base class destructor will still be called, see the FAQ (11.12). Note also that since the base class destructor is virtual, the derived class destructor is automatically virtual (whether you define one or not), see FAQ (20.7).
Why do you think the destructor of derived class should be called? You only delete base and it is an instance of the base class.
No the definition of the destructor is not required - you may ommit it.

Why should the destructor of base classes be virtual?

in C++: Why should the destructor of base classes be virtual?
The better question is when and why. Your question indicates that you think all base classes should have virtual destructors, which is not quite true.
It would make it impossible to apply the empty base class optimization, and could multiply the size of classes up to 16 times than what it would be without virtual on common platforms.
A virtual destructor is needed when you delete an object whose dynamic type is DerivedClass by a pointer that has type BaseClass*. The virtual makes the compiler associate information in the object making it able to execute the derived class destructor. Missing the virtual in such case causes undefined behavior.
If you don't need this, and your class is only used as a base class, it's best to make the destructor protected, thus preventing that users accidentally delete in the described way.
You want them to be virtual so that all subclass destructors are automatically called when the object is destroyed, even if it is destroyed through a pointer to the base class. In the following code:
class base {
public:
virtual ~base() { }
};
class derived : public base {
public:
~derived() { } // Inherits the virtual designation
};
int main(void)
{
base *b = new derived;
delete b;
}
The derived destructor will only be called if the base destructor is virtual.
As Magnus indicates, you don't have to do this if you aren't taking advantage of polymorphism. However, I try to develop the habit of declaring all my destructors virtual. It protects me against the case where I should have declared them virtual but forget to do so. As Johannes indicates, this habit can impose a small space and performance penalty when the virtual designation is not needed.
They dont have to be virtual unless you are using polymorphism. If you do use polymorphism they need to be virtual so that the destructors of inherited classes are guaranteed to be called, so inherited classes can do their clean up.
For situations like this:
class A
{
virtual ~A();
};
class B:A
{
~B();
};
A *a = new B(); //legal, since it's a downcast
delete a; //Unless the destructor is virtual, ~A() is called here instead of ~B().
It should be virtual to ensure that the destructor of the inherited classes are the ones actually getting called at runtime instead of the base class destructor being called.

Who calls the Destructor of the class when operator delete is used in multiple inheritance

This question may sound too silly, however , I don't find concrete answer any where else.
With little knowledge on how late binding works and virtual keyword used in inheritance.
As in the code sample, when in case of inheritance where a base class pointer pointing to a derived class object created on heap and delete operator is used to deallocate the memory , the destructor of the of the derived and base will be called in order only when the base destructor is declared virtual function.
Now my question is :
1) When the destructor of base is not virtual, why the problem of not calling derived dtor occur only when in case of using "delete" operator , why not in the case given below:
derived drvd;
base *bPtr;
bPtr = &drvd; //DTOR called in proper order when goes out of scope.
2) When "delete" operator is used, who is reponsible to call the destructor of the class? The operator delete will have an implementation to call the DTOR ? or complier writes some extra stuff ? If the operator has the implementation then how does it looks like , [I need sample code how this would have been implemented].
3) If virtual keyword is used in this example, how does operator delete now know which DTOR to call?
Fundamentaly i want to know who calls the dtor of the class when delete is used.
<h1> Sample Code </h1>
class base
{
public:
base(){
cout<<"Base CTOR called"<<endl;
}
virtual ~base(){
cout<<"Base DTOR called"<<endl;
}
};
class derived:public base
{
public:
derived(){
cout<<"Derived CTOR called"<<endl;
}
~derived(){
cout<<"Derived DTOR called"<<endl;
}
};
I'm not sure if this is a duplicate, I couldn't find in search.
int main()
{
base *bPtr = new derived();
delete bPtr;// only when you explicitly try to delete an object
return 0;
}
This is due to tha fact that in this case the compiler know everything about the object to be destructed which in this case is drvd and is of type derived. When drvd goes out of scope the compiler inserts code to call its destructer
delete is a keyword for compiler. When compiler see delete it inserts the code to call the destructer and the code to call operator delete to deallocate the memory.Please keep in mind that keyword delete and operater delete are different.
When compiler sees keyword delete being used for a pointer it needs to generate code for its proper destruction. For this it needs to know the type information of the pointer. The only thing the compiler know about the pointer is the pointer type, not the type of object to which the pointer is pointing to. The object to which the pointer is pointing to may be a base class or a derived class. In some cases the type of object may be very clearly defined for example
void fun()
{
Base *base= new Derived();
delete base;
}
But in most cases it is not, for example this one
void deallocate(Base *base)
{
delete base;
}
So the compiler does not know which destructer to call of base or of derived. This is the way then it works
If the Base class does not have a virtual function (member function or destructer). It directly insetrts thr code to call the destructer of base class
If the Base class has virtual functions, then the compiler takes the information of destructer from vtable.
If destructer is not virtual. The vtable will have the address of base destructer and thats what will be called. This is not right since the proper destructer is not being called here. This is why it is always recommended to declare destructer of base class as virtual
If the destructer is virtual the vtable will have correcte address of destructer and compiler will insert proper code over there
+1 Good question BTW.
Look at how the virtual mechanism works for a non destructor method and you'll find a destructor behaves no differently.
There are 2 mechanism in play which may confuse the issue a little
.
Firstly a mechanism that isn't virtual is happening on construction and destruction of an object. The object is constructed from base class to derived class, in that order, and when destructed the destructor order is the reversed, so derived to based class. Nothing new here.
Consider calling a non virtual method on a based class pointer to a derived class object, what happens? The base class implementation is called. Now consider calling a virtual method from a base class pointer to a derived class object, what happens? The derived version of the method is called. Nothing you didn't already know.
Lets now consider the destructor scenario. Call delete on a base class pointer to a derived class object which has a non virtual destructor. The base class destructor is called, and if the base class had been derived from another class, then it's destructor would get called next. Because the virtual mechanism isn't in play , the derived destructor won't be called because destruction starts from the destructor you call in the hierarchy and works it way down to the base class.
Now consider the virtual destructor case. delete is called on a based class pointer to a derived class object. What happens when you call any virtual method on a base class pointer? The derived version gets called. So our derived class destructor is called . What happens during destruction, the object destructs from derived destructor to base class, but this time we started the destruction at the derived class level because of the virtual method mechanism.
Why does a stack object with either a non virtual or virtual destructor destruct from derived to base class when it goes out of scope? Because the destructor of the declared class is called in this case and the virtual mechanism has nothing to do with it.
The compiler generates all necessary code to call destructors in the right order, whether it be a stack object or member variable going out of scope, or a heap object being deleted.
You instantiate the derived type, when it goes out of scope it calls the destructor, virtual or not.
The compiler will generate code which makes a call to the destructors. It does not all happen on compile time. Code generation does, but lookin up what the address of the dtor is happens at runtime. Think about the case where you have more then 1 derived type and you do the delete using a base pointer.
A base class destructor needs to be virtual to make a polymorphic delete call the dtor of the derived type.
If you want to find out more try overloading new and delete.