How do virtual destructors work? - c++

Few hours back I was fiddling with a Memory Leak issue and it turned out that I really got some basic stuff about virtual destructors wrong! Let me put explain my class design.
class Base
{
virtual push_elements()
{}
};
class Derived:public Base
{
vector<int> x;
public:
void push_elements(){
for(int i=0;i <5;i++)
x.push_back(i);
}
};
void main()
{
Base* b = new Derived();
b->push_elements();
delete b;
}
The bounds checker tool reported a memory leak in the derived class vector. And I figured out that the destructor is not virtual and the derived class destructor is not called. And it surprisingly got fixed when I made the destructor virtual. Isn't the vector deallocated automatically even if the derived class destructor is not called? Is that a quirk in BoundsChecker tool or is my understanding of virtual destructor wrong?

Deleting a derived-class object through a base-class pointer when the base class does not have a virtual destructor leads to undefined behavior.
What you've observed (that the derived-class portion of the object never gets destroyed and therefore its members never get deallocated) is probably the most common of many possible behaviors, and a good example of why it's important to make sure your destructors are virtual when you use polymorphism this way.

If the base class does not have a virtual destructor, then the result of your code is undefined behaviour, not necessarily the wrong destructor being called. This is presumably what BoundsChecker is diagnosing.

Although this is technically undefined, you still need to know the most common method of failure in order to diagnose it. That common method of failure is to call the wrong destructor. I don't know of any implementation that will fail in any other manner, though admittedly I only use two implementations.
The reason this happens is the same reason the 'wrong' function will get called when you try to override a non-virtual member function and call it through a base pointer.

If the destructor is not virtual then the Base destructor will be called. The base destructor cleans up the Base object and finishes. There is no way for the base object destructor to know about the derived object, it must be the derived destructor called, and the way to do that, as with any function, is to make the destructor virtual.

From the C++ FAQ Lite: "When should my destructor be virtual?" Read it here.
(C++ FAQ Lite is an excellent source for all your questions related to C++, by the way).

In C++, a trivial destructor is a recursively defined concept -- it's a destructor that the compiler wrote for you when every member of the class (and every base class) has a trivial destructor. (There's a similar concept called the trivial constructor.)
When an object with a nontrivial destructor is included in an object (like the vector in your example), then the destructor of the outside object (like your Derived) in is no longer trivial. Even though you didn't write destructor, the C++ compiler automatically wrote a destructor that calls the destructors of any members that have destructors.
So, even though you didn't write anything, the caveats of writing a non-virtual destructor still apply.

if you are coming from c#, then you were right in wondering why vector is not automatically de-allocated. But in c++, automatic memory management is not availble unless you use the Microsoft Manged Extesions to C++ (C++/CLI).
since there is no destructor in Base class that is virtual, the derived class object will never be freed and there-by you leak the memory allocated for the vector data member of the the derived class.

Destructor is the member function of the class whose name is the same name of the class name and it is preceded by the tilde sign(~). Destructor is used to destroy the object of the class when object goes out of scope or you can say that all clean up of class destruction are to be done in destructor. All the memory gets allocated during construction of the object in class gets destructed (or memory release) when object goes out of scope.
Find more details with example on BoundsCheck

Related

C++ Possible to make a destructor NOT call the destructor of class members and the destructor of the base class?

Is there a way to make a destructor of a class NOT call the destructor of one of the class members and/or NOT call the destructor of its base class?
In case this is not possible, is creating certain class members with placement-new and destructing (/not-destructing) them manually a possible workaround? Thanks!
EDIT:
The reason I need this: Class C owns object M. M has a non-trivial destructor. C is friend of M and manages M in a way that there is no need to call M's destructor. It is OK to call it but it means performance overhead. (it's a problem in this case.)
I was thinking to make an a derived class from M that has a destructor that does nothing, but then that would still call the destructor of the base.
At construction time, C++ ensures that the subclasses contructors are first called, then the members are contructed, and finally the appropriate constructor is applied. At destruction time the symetric is done.
That means that you cannot prevent the application of a base class destructor, nor of any member constructor, as soon as the object is destructed. If you want to only destruct some, you must find a way to not destruct the object (just use a raw pointer...) and manually call destructors on what you want. But you certainly do not want to do that!
C++ is very confident on the programmer skills, so it is easy to write a program invoking undefined behaviour. If you find yourself trying to subvert the C++ compiler to not call the destructor of a base class or of a member, you have a major problem. The member you do not want to destroy should not be a member but more probably a pointer (raw or shared) or a reference to an external object that will have its own lifetime management. And the base class should probably also be a pointer or reference to an external object, and here again the lifetime can (and should) be managed outside of the class.
If the destructor has observable side-effects, then it would be undefined behaviour to end the lifetime of the object without invoking the destructor. This is covered in C++14 [basic.life]/4:
A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitly calling the destructor for an object of a class type with a non-trivial destructor. For an object of a class type with a non-trivial destructor, the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released; however, if there is no explicit call to the destructor or if a delete-expression is not used to release the storage, the destructor shall not be implicitly called and any program that depends on the side effects produced by the destructor has undefined behavior.
So, there is no way to get around it. Perhaps you could redesign your code so that the destructor doesn't execute any unnecessary statements, or something.

Deleting an object polymorphically

Base* optr=new Derived();
delete optr;
I know that if Base class has a non-virtual destructor, only ~Base() destructor is going to be called when deleting optr pointer. But I found out that even without ~Derived() destructor being called the memory that was taken by the Derived Object was freed. So my question is can an object get freed without calling it's destructor?
If the answer is yes, can I use a non-virtual destructor if my Derived class does not contain any dynamically allocated variables so I don't care if it did not get called?
From the viewpoint of standard C++, the answer is simple: the result is undefined behavior, so what you get is completely unpredictable
I'm a little puzzled why you'd care anyway. If you can eliminate all the virtual functions from a class, each instance becomes smaller (by the size of a vtable pointer). Using such a thing as a base class rarely makes sense though -- for use as a base class to be sensible, you pretty much need to have at least one virtual function in the base for the derived class to override. Once you have a virtual function (any virtual function) adding more is essentially free -- objects don't grow any larger by adding more virtual functions.
To answer your question directly: yes, the memory can be freed without the destructor being invoked. The real question is what will happen when you make that happen (and there's really no answer to that question).
The thing about undefined behaviour is that sometimes it seems to work.
The standard doesn't say that your program must fail if the base class destructor is not virtual, it says that it must work when the destructor is virtual.
You might be able to get away without a virtual destructor if the derived class doesn't add any members. The memory footprints will be the same, and the members will all be destroyed in the base class destructor. However this is not guaranteed by the standard and you'll be at the mercy of your compiler's implementation.
There're two distinct things: calling object destructor, and freeing the memory.
Standard heap specification does not require you to pass the memory block size when you free it. That is, the heap implementation should deduce the memory block size itself.
Hence - yes. If you Derived does not contain extra things that must be destroyed by appropriate means (such as memory allocated on heap, file handles and etc.) - you don't need the virtual destructor.
Look over here : Virtual destructor

How/when do I use a virtual destructor?

I'm currently writing a program with the following polymorphic hierarchy: Base: Multinumber. Derived: Pairs, Complex, Rational. Multinumber is a virtual class and is never instantiated.
During the course of my program I frequently dynamically manage the base classes so I need a destructor. My question is this: how do I make the destructor virtual? In my Multinumber.h file right now I have this:
virtual ~Multinumber();
In my Multinumber.cpp:
Multinumber::~Multinumber()
{
}
And in all of my derived classes I have this:
Rational::~Rational()
{
}
I have nothing in any of my derived.h files. Unfortunately, this does not compile. Rather, I get this error:
Complex.cpp|75|error: definition of implicitly-declared 'virtual Complex::~Complex()'
What is wrong with my syntax? Thanks for any help you can give me.
Just declaring the virtual destructor in the base, and giving it the empty definition, is sufficient. For the other classes you do not need to do anything at all, unless there's actual work for those destructors to do.
The point of the virtual declaration in the base class is to ensure that the destructor can be invoked polymorphically (so that Base* d = new Derived(); delete d; works correctly, calling the Derived destructor instead of the Base destructor). You then have to define that destructor (even if it does no work) because you declared it.
However, for all of the derived classes, if you don't specify anything, the default "call destructors for members and bases" destructor gets generated for them, and everything works as you need it to. Unless, again, you need to do anything else to destruct the object properly.
As Dark Falcon noted, you need a declaration in the base for every member that you define, including destructors. So if you do write Complex::~Complex, then it must be declared in the Complex class definition, even though you inherit from a class that declares and defines a destructor. (Destructors, like constructors, aren't actually inherited anyway; the default "call recursively on members and bases" behaviour isn't really the same thing. These functions are special, since they manage the object lifetime, rather than using the object.)
Within the class Complex, you also need to have a declaration for the destructor:
~Complex();
Note that virtual is optional here. The destructor will be virtual because the base's destructor is virtual.
When to declare a destructor virtual?
I recommend you to follow this algorithm to decide whether you should declare a destructor virtual or not.
Is your class intended to be used as a base class?
No: Declare non-virtual destructor (avoids v-pointer on each object of the class) and remember not to derive from concrete classes.
Yes: Go to next question.
Is your base class abstract? (i.e. any virtual pure methods?)
No: Try to make you base class abstract by redesigning your hierarchy [1] (i.e. don't allow you base class to be instantiated).
Yes: Go to next question.
Do you want to allow polymorphic deletion though a base pointer?
No: Declare protected virtual destructor to avoid the unwanted usage.
Yes: Declare public virtual destructor (no overhead in this case).
References:
[1]: S. Meyers. More Effective C++, Item 33 (Addison-Wesley, 1996).
[2]: "Virtuality" http://www.gotw.ca/publications/mill18.htm
What is wrong with my syntax?
The following:
And in all of my derived classes I
have this:
Rational::~Rational() { }
No you don't. You didn't do it for Complex.
The question is: When to not declare the destructor virtual? There are no drawbacks to declaring a destructor virtual.

Should C++ 'interfaces' have a virtual destructor [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Destructors for C++ Interface-like classes
Consider a simple example of a C++ abstract class, used to model an interface:
class IAnimal
{
virtual void walk()=0;
virtual ~IAnimal(){}
};
Is it better to have the destructor, or not? I don't think the destructor can be pure virtual, at least my tests give linker errors, so should an empty destructor be included?
EDIT: sorry, typo. It's a destructor not a constructor.
You should always use a virtual destructor with interfaces. Case in point:
IAnimal* animal = new Lion();
delete animal;
Now what destructor is it going to use? Definately not the Lion's destructor because the interface doesn't know about Lion's destructor.
So, have this if your interface has no memory management:
virtual ~IAnimal(){}
Check out this article by Herb Sutter
Especially this part:
For the special case of the destructor
only:
Guideline #4: A base class destructor
should be either public and virtual,
or protected and nonvirtual.
This assumes that base class is an 'interface' class as it mostly should be.
This depends on whether you intend to manage the lifetime of objects polymorphically, using pointers to the interface class.
If you do, then the destructor must be virtual, in order to correctly delete the objects. Deleting a base-class pointer that doesn't have a virtual destructor is invalid, and gives undefined behaviour.
If you don't, then you should enforce this by making the destructor non-virtual and protected, so only derived classes can be deleted.
I think it should be a pure virtual destructor for interfaces, and all other methods are pure virtual as well.
The only reason not to make the destructor virtual would be to save the space needed for the vptr. As you need the vptr anyway because you have another virtual function, I would make the destructor virtual.
an empty constructor should probably be included since a typical use of an interface involves putting a pointer to some concrete object in a container, which will otherwise call the wrong destructer and will not clean the memory correctly.
so if anyone is going to delete derived objects through a pointer to Ianimal make a virtual destructor, else make your destructor nonvirtual and protected.
making your destructor pure virtual is probably not such a good idea, since it forces implementers of derived classes to override your destructor, eventhough they might want to do nothing

Virtual destructor: is it required when not dynamically allocated memory?

Do we need a virtual destructor if my classes do not allocate any memory dynamically ?
e.g.
class A
{
private:
int a;
int b;
public:
A();
~A();
};
class B: public A
{
private:
int c;
int d;
public:
B();
~B();
};
In this case do we need to mark A's destructor as virtual ?
The issue is not whether your classes allocate memory dynamically. It is if a user of the classes allocates a B object via an A pointer and then deletes it:
A * a = new B;
delete a;
In this case, if there is no virtual destructor for A, the C++ Standard says that your program exhibits undefined behaviour. This is not a good thing.
This behaviour is specified in section 5.3.5/3 of the Standard (here referring to delete):
if the static type of the operand 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 behavior is
undefined.
The purpose of virtual destructor (i.e. the purpose of making a destructor virtual) is to facilitate the polymorphic deletion of objects through delete-expression. If your design does not call for polymorphic deletion of objects, you don't need virtual destructors. Referring to your example, if you'll ever have to delete an object of type B through a pointer of type A * (polymorphic deletion), you'll need virtual destructor as high up in the hierarchy as A. That's how it looks from a formal point of view.
(Note, BTW, as Neil said, that what's important is how you create/delete your class objects, not how classes manage their internal memory.)
As for the good programming practices... It depends on your intent and your design in the end. If your classes are not designed to be polymorphic at all (no virtual methods whatsoever), then you don't need virtual destructors. If your class is polymorphic (have at least one virtual method), then making the destructor virtual "just in case" might be a very good idea, and in this case it bears virtually zero performance/memory penalty with it.
The latter is usually expressed as a rather well-known good practice guideline: if your class has at least one virtual method, make the destructor virtual as well. Although from the formal point of view a virtual destructor might not be really needed there, it is still a pretty good guideline to follow.
Classes that have no resources but can form polymorphic hierarchies should always define empty virtual destructors, except that it is perfectly sufficient to define an explicit empty (and even pure) virtual destructor at the very base of the hierarchy. All other destructors will become virtual automatically, even if they are defined implictly by the compiler. I.e. you don't have to explicitly define an empty destructor in every class. Just the base is enough.
Freeing memory is not the only critical function a destructor can perform. It can also be used to reset global state for instance. Not doing this won't leak memory but could potentially cause other issues in your program.
Additionally, even if your destructor doesn't do anything useful today, it may at some point in the future. There's no real reason to avoid a virtual destructor if you have inheritance so why not just add it and sleep better at night?
The destructor of the parent class is always automatically called, and the default dtor is always generated if there's no explicit dtor declared. In your example, neither A nor B needs to have a non-trivial dtor.
If you class has virtual functions, an additional virtual dtor doesn't hurt, and is good practice. In case you class allocates memory or any other resource (like opening a file), a dtor is needed to free that resource again upon destruction.
The purpose of declaring destructor as virtual is to be able to invoke the derived class's destructor whenever you call delete on a pointer of type Base which is pointing to object of type Derived. Not doing so would result in undefined behavior.
The assumption that you need not mark destructor as virtual if you are not allocating memory dynamically implies that you do not need to call derived class destructor if you are not allocating memory dynamically, which is wrong. As you may still do several other operations in your derived class's destructor other than just deallocating the dynamically allocated memory. Examples would be closing an open file, logging some information etc.
If your only concern is memory, maybe you should start by protecting base class destructor (and/or maybe others). Then if something does not compile, you'll see why. Ref: boost::any ways.