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

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.

Related

Virtual destructor use cases

I' ve read some articles, and as they say, main virtual destructor use cases are:
derived classes may have dynamic data allocation from heap, i.e. "own" that data object. So, they need some deletion routine in destructor. Deletion through base class pointer requires virtual declaration of destructors in all derived class till those with dynamic data allocation (base class also requires it)
this class has virtual methods. But this is unclear for me. Just calling virtual methods through base class pointer always results in the-most-derived-realization calls. They only exclusion for that rule is construction phase. Literaly, during it this object is not a derived type yet, even if later will be. Ok, what about destruction phase? As I understood, the rule is in the backward order. No matter, was destructor of some class in hierarchy declared as virtual, during each destructor this pointer is used as if of this class type, any derived were already been destroyed due to virtual d-r, or not destroyed (and that hypothetically may be ok in some design). Maybe this is the case, why d-r must be virtual? Vtable will have entries for derived class, and calling virtual methods in some base class from d-r will result in UB? Ok, but this rule applies only to case when this class calls some virtual methods in d-r, and they do have realization in derived classes.
My opinion, that there is also may be a case with no dynamic data allocation, no virtual methods in all hierarchy, but still derived destructors may do some critical tasks upon deletion (syncs, unlocks and so on). And we need virtual d-r in base class. May be such cases are results of bad design.
But anyway, developer of some public class cannot 100% know, if derived class will or not use some virtual methods in d-r, or allocate dynamic data. So, am I correct to say, that any public class, not declared as final, has to declare d-r as virtual? Only final keyword guarantees that any pointer to this class will always be of this type, and so, could be safely deleted non-virtually.
If a derived object is deleted through a pointer to the base class, then (and only then) the base class destructor must be virtual. Otherwise it is undefined behaviour. There are no other relevant rules.
If the class had a virtual function anyway, then no overhead is introduced. If the class did not have any other virtual functions, then the base class designer has to consider the trade between adding the runtime penalty of a virtual destructor, vs. the risk that a user of the class might try to delete a derived object through the base class pointer.
Here is a link to a similar discussion, with Standard quotes

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

Are there any specific reasons to use non-virtual destructors?

As I know, any class that is designated to have subclasses should be declared with virtual destructor, so class instances can be destroyed properly when accessing them through pointers.
But why it's even possible to declare such class with non-virtual destructor? I believe compiler can decide when to use virtual destructors. So, is it a C++ design oversight, or am I missing something?
Are there any specific reasons to use non-virtual destructors?
Yes, there are.
Mainly, it boils down to performance. A virtual function cannot be inlined, instead you must first determined the correct function to invoke (which requires runtime information) and then invoke that function.
In performance sensitive code, the difference between no code and a "simple" function call can make a difference. Unlike many languages C++ does not assume that this difference is trivial.
But why it's even possible to declare such class with non-virtual destructor?
Because it is hard to know (for the compiler) if the class requires a virtual destructor or not.
A virtual destructor is required when:
you invoke delete on a pointer
to a derived object via a base class
When the compiler sees the class definition:
it cannot know that you intend to derive from this class -- you can after all derive from classes without virtual methods
but even more daunting: it cannot know that you intend to invoke delete on this class
Many people assume that polymorphism requires newing the instance, which is just sheer lack of imagination:
class Base { public: virtual void foo() const = 0; protected: ~Base() {} };
class Derived: public Base {
public: virtual void foo() const { std::cout << "Hello, World!\n"; }
};
void print(Base const& b) { b.foo(); }
int main() {
Derived d;
print(d);
}
In this case, there is no need to pay for a virtual destructor because there is no polymorphism involved at the destruction time.
In the end, it is a matter of philosophy. Where practical, C++ opts for performance and minimal service by default (the main exception being RTTI).
With regards to warning. There are two warnings that can be leveraged to spot the issue:
-Wnon-virtual-dtor (gcc, Clang): warns whenever a class with virtual function does not declare a virtual destructor, unless the destructor in the base class is made protected. It is a pessimistic warning, but at least you do not miss anything.
-Wdelete-non-virtual-dtor (Clang, ported to gcc too): warns whenever delete is invoked on a pointer to a class that has virtual functions but no virtual destructor, unless the class is marked final. It has a 0% false positive rate, but warns "late" (and possibly several times).
Why are destructors not virtual by default?
http://www2.research.att.com/~bs/bs_faq2.html#virtual-dtor
Guideline #4: A base class destructor should be either public and virtual, or protected and nonvirtual.
http://www.gotw.ca/publications/mill18.htm
See also: http://www.erata.net/programming/virtual-destructors/
EDIT: possible duplicate? When should you not use virtual destructors?
Your question is basically this, "Why doesn't the C++ compiler force your destructor to be virtual if the class has any virtual members?" The logic behind this question is that one should use virtual destructors with classes that they intend to derive from.
There are many reasons why the C++ compiler doesn't try to out-think the programmer.
C++ is designed on the principle of getting what you pay for. If you want something to be virtual, you must ask for it. Explicitly. Every function in a class that is virtual must be explicitly declared so (unless its overriding a base class version).
if the destructor for a class with virtual members were automatically made virtual, how would you choose to make it non-virtual if that's what you so desired? C++ doesn't have the ability to explicitly declare a method non-virtual. So how would you override this compiler-driven behavior.
Is there a particular valid use case for a virtual class with a non-virtual destructor? I don't know. Maybe there's a degenerate case somewhere. But if you needed it for some reason, you wouldn't be able to say it under your suggestion.
The question you should really ask yourself is why more compilers don't issue warnings when a class with virtual members doesn't have a virtual destructor. That's what warnings are for, after all.
A non-virtual destructor seems to make sense, when a class is just non-virtual after all (Note 1).
However, I do not see any other good use for non-virtual destructors.
And I appreciate that question. Very interesting question!
EDIT:
Note 1:
In performance-critical cases, it may be favourable to use classes without any virtual function table and thus without any virtual destructors at all.
For example: think about a class Vector3 that contains just three floating point values. If the application stores an array of them, then that array could be store in compact fashion.
If we require a virtual function table, AND if we'd even require storage on heap (as in Java & co.), then the array would just contain pointers to actual elements "SOMEWHERE" in memory.
EDIT 2:
We may even have an inheritance tree of classes without any virtual methods at all.
Why?
Because, even if having "virtual" methods may seem to be the common and preferable case, it IS NOT the only case that we - the mankind - can imagine.
As in many details of that language, C++ offers you a choice. You can choose one of the provided options, usually you will choose the one that anyone else chooses. But sometimes you do not want that option!
In our example, a class Vector3 could inherit from class Vector2, and still would not have the overhead of virtual functions calls. Thought, that example is not very good ;)
Another reason I haven't seen mentioned here are DLL boundaries: You want to use the same allocator to free the object that you used to allocate it.
If the methods live in a DLL, but the client code instantiates the object with a direct new, then the client's allocator is used to obtain the memory for the object, but the object is filled in with the vtable from the DLL, which points to a destructor that uses the allocator the DLL is linked against to free the object.
When subclassing classes from the DLL in the client, the problem goes away as the virtual destructor from the DLL is not used.

How do virtual destructors work?

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

Can the default destructor be generated as a virtual destructor automatically?

Can the default destructor be generated as a virtual destructor automatically?
If I define a base class but no default destructor, is there a default virtual destructor
generated automatically?
No. There is a cost associated with making a method virtual, and C++ has a philosophy of not making you pay for things that you don't explicitly state that you want to use. If a virtual destructor would have been generated automatically, you would have been paying the price automatically.
Why not just define an empty virtual destructor?
In C++ 11 you can use:
class MyClass
{
// create a virtual, default destructor
virtual ~MyClass() = default;
};
Yes, by inheriting from a base class with a virtual destructor. In this case, you already pay the price for a polymorphic class (e.g. vtable).
No, all destructor's are by default NOT virtual.
You will need to define a virtual destructor on all the base classes
In addition to that.
To quote Scott Meyers in his book "Effective C++":
The C++ language standard is
unusually clear on this topic. When
you try to delete a derived class
object through a base class pointer
and the base class has a non-virtual
destructor (as EnemyTarget does), the
results are undefined
In practice, it's usually a good idea to define a class with a virtual destructor if you think that someone might eventually create a derived class from it. I tend to just make all classes have virtual destructor's anyway. Yes, there is a cost associated with that, but the cost of not making it virtual more often that not out weighs a measly bit of run-time overhead.
I suggest, only make it non-virtual when you're absolutely certain that you want it that way rather than the rely on the default non-virtual that the compilers enforce. You may disagree, however (in summary) I recently had a horrid memory leak on some legacy code where all I did was add a std::vector into one of the classes that had existed for several years. It turns out that one of it's base classes didn't have a destructor defined (default destructor is empty, non-virtual!) and as no memory was being allocated like this before no memory leaked until that point. Many days of investigation and time wasted later...
Uri and Michael are right -- I'll just add that if what's bugging you is having to touch two files to declare and define the destructor, it's perfectly all right to define a minimal one inline in the header:
class MyClass
{
// define basic destructor right here
virtual ~MyClass(){}
// but these functions can be defined in a different file
void FuncA();
int FuncB(int etc);
}
Currently, Uri is right. On the other hand, after you have declared a virtual method in your class, you are paying the price for the existence of the virtual table anyway. In fact, the compiler will warn you if your class has a virtual method, but no virtual destructor. This could become a candidate for automatic generation of the default virtual destructor instead of the pesky warning.
No. You need to declare it as virtual.
Some people stated that it is never defaulted to virtual. That's not exactly true.
Even though destructors are not inherited, if a base class declares its destructor virtual, the derived destructor always overrides it.
This means that if the base class has a virtual destructor you don't have to define a destructor of the derived class as virtual nor explicitly write:
/// All of these are unnecessary and won't change the destruction behavior
/// as long as Class inherits from a base class with a virtual destructor
virtual ~Class() = default;
// or
~Class() override = default;
// or
~Class() {}