When should your destructor be virtual? [duplicate]
Asked Answered
S

6

46

Possible Duplicate:
When to use virtual destructors?

When should your C++ object's destructor be virtual?

Solley answered 14/7, 2009 at 1:37 Comment(3)
Copied from <blogs.msdn.com/oldnewthing/archive/2004/05/07/127826.aspx >?Wagtail
lot of related stuff: stackoverflow.com/search?q=virtual+destructorWitless
try this link #461703 .It might helpMiceli
S
61
  1. You need virtual destructor when at least one of class methods is virtual.

This is because the reason for virtual method is that you want to use polymorphism. Meaning you will call a method on the base class pointer and you want the most derived implementation - this is the whole point of polymorphism.

Now if you did not have virtual destructor and through the pointer to base class you call destructor you end up calling base class destructor. In this case you want polymorphism to work on your destructor as well, e.g. through calling destructor on your base class you want to end up calling destructor of your most derived class not your base class.

class A
{
   virtual void f() {}
   ~A() {}
}

class B : public A
{
   void f() {}
   ~B() {}
}

A * thing = new B();
thing->f(); // calls B's f()
delete thing; // calls ~A(), not what you wanted, you wanted ~B()

having ~A() virtual turns on polymorphism

virtual ~A() {}

So when you now call

delete thing;

~B() will be called.

You would declare virtual destructors when you design class as an interface e.g. you expect it to be extended or implemented. A good practice in that case is to have a interface class (in the sense of Java interfaces) with virtual methods and virtual destructor and then have concrete implementation classes.

You can see that STL classes don't have virtual destructors so they are not supposed to be extended (e.g. std::vector, std::string ...). If you extend std::vector and you call destructor on base class via pointer or reference you will definitely not call your specialized class destructor which may lead to memory leaks.

Stickpin answered 14/7, 2009 at 2:23 Comment(1)
The exact answer I was looking for after choosing the wrong answer in the pluralsight skill IQ question, thanksBland
W
33

From Stroustrup's C++ Style and Technique FAQ:

So when should I declare a destructor virtual? Whenever the class has at least one virtual function. Having virtual functions indicate that a class is meant to act as an interface to derived classes, and when it is, an object of a derived class may be destroyed through a pointer to the base.

Lots of additional info on when your destructor should be virtual on the C++ FAQ. (thanks Stobor)

What is a virtual member? From the C++ FAQ:

[20.1] What is a "virtual member function"?

From an OO perspective, it is the single most important feature of C++: [6.9], [6.10].

A virtual function allows derived classes to replace the implementation provided by the base class. The compiler makes sure the replacement is always called whenever the object in question is actually of the derived class, even if the object is accessed by a base pointer rather than a derived pointer. This allows algorithms in the base class to be replaced in the derived class, even if users don't know about the derived class.

The derived class can either fully replace ("override") the base class member function, or the derived class can partially replace ("augment") the base class member function. The latter is accomplished by having the derived class member function call the base class member function, if desired.

Wellintentioned answered 14/7, 2009 at 1:41 Comment(6)
That's not the only case, though...Wagtail
+1 nice copy paste quote from Mr S., can't really beat that answerStickpin
To be precise, what about when the child class of a parent with no virtual functions defines a member which requires cleanup, but which isn't contained in the parent? The lack of a virtual destructor would mean "delete parent" would not call the child class's destructor...Wagtail
parashift.com/c++-faq-lite/virtual-functions.html#faq-20.7Wagtail
In that case, Stobor, there was little point instantiating the derived class. There is no way to access the derived class's methods without a dynamic_cast, which implies knowledge of the object type. That knowledge could be used to dynamic_cast before the destructor too. Of course, the virtual method thing is just a rule of thumb. Not surprising your contrived example shoots a hole in itDispensatory
In the astonishingly rare situation where Stroustrup's deduction doesn't hold (i.e. the class is intended to act as an interface to derived classes, but the desired interface is that an object of a derived class MAY NOT be destroyed through a pointer to the base) then IIRC you can have a protected non-virtual destructor. It's next to pointless making it non-virtual AFAIK, since virtual destructors are hardly a common performance bottleneck. But stopping clients from deleting stuff themselves might be a useful restriction, and it could then be non-virtual if desired.Sleekit
T
6

I've recently come to conclude that the fully correct answer is this:

Guideline #4: A base class destructor should be either public and virtual, or protected and nonvirtual.

And of course Herb Sutter gives the rationale to his claim. Note that he does go beyond the usual answers "when someone will delete a derived-class object via a base-class pointer" and "make your destructor virtual if your class has any virtual functions".

Timoshenko answered 19/7, 2009 at 13:34 Comment(1)
I would not narrow it down to those 2 options. You use tools to build what is required, in this case features of programming language. If you create every public destructor public you turn on polymorphism for each of those classes, probably in 90% of those cases you don't need that and you end up with unnecessary overhead.Stickpin
B
3

If you will (or even might) destroy objects of a derived class through a base class pointer, you need a virtual destructor.

I take the approach that if I'm going to derive from a class AT ALL, then it shall have a virtual destructor. There are effectively no cases in the code I write where the performance implications of a virtual destructor matter, and even if it's not actually needed today, it might end up needing it in the future when the class is modified.

Basically: Put virtual on all base class destructors unless you have a good, well-thought out reason not to.

That's just another rule of thumb, but it's one that keeps you from making later mistakes.

Burley answered 14/7, 2009 at 2:26 Comment(0)
C
0

Always.

Unless I'm really concerned with the storage and performance overhead of a vtable, I always make it virtual. Unless you have a static analysis tool to verify for you that your destructor is virtual in the right cases, it's not worth making a mistake and failing to make a virtual destructor when it's needed.

Chicle answered 14/7, 2009 at 2:23 Comment(4)
C++ didn't give you that flexibility just so you could throw it away. Put another way, "Unless I'm really concerned with the storage and performance overhead of a vtable, I'm going to use an easier language like Python or Lua."Allopathy
"C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off" --Stroustrup. C++ is an extremely useful language in the right situation, but you have to protect yourself. Either always make it virtual, or find a static analysis tool to protect yourself, or manually review each destructor when someone changes your code.Chicle
@Jared: or introduce sensible rules and means of documenting what classes can be used as base classes, and how. You don't have to review the destructor for every code change, just for changes which alter the polymorphism characteristics of the class (none/static/dynamic). That said, if you tend to use dynamic polymorphism for everything, then it's certainly easier to make classes inheritance-ready unless proven otherwise. Ex-Java programmers probably need more virtual destructors and methods than ex-C programmers, so I guess could opt for "virtual by default".Sleekit
@Tom: yes, you can just throw the flexibility away. C++ gives you the flexibility so you can remove it when you want, or add it when you want. Lesser languages enforce it all the time. So for C++, you might as well put virtual dtors everywhere, except in those cases where you've thought about it and decided you don't want them.Shade
G
-1

A base class object should have a virtual destructor, when it is necessary for the base class to do its own cleanup. This is to say, if you have allocated resources in the base class it is necessary for the base class to cleanup, by declaring its destructor virtual you guarantee that this cleanup will be done (assuming you wrote the cleanup correctly).

In general, methods can be defined virtual in a base class, this will allow derived classes to override the virtual methods, implementing their own derived specific implementation. I find this is most clearly demonstrated with a simple example. Say we have a base class 'Shape', now all derived classes may be required to have the ability to draw. The 'Shape' object will not know how to draw classes derived from it, so in the 'Shape' class we define a virtual draw function. ie (virtual void draw();). Now in each base class we can override this function, implementing specific drawing code (ie. a square is drawn differently from a circle).

Gorse answered 14/7, 2009 at 1:45 Comment(2)
This is not quite correct e.g. If a base class A (non virtual destructor defined) doesn't have resources, and class B (a subclass of A) does have resources and we have something like B *b = new B(); A *a = static_cast<A>(b); delete a; then the result is actually undefined in the standard. It might free the resources, or it might not. More often than not memory is leaked. So the correct answer would be - if you've got sub-classes, then the base class needs to have a virtual destructor to ensure resources are correctly freed.Cyndycynera
it has been included in the guidelines : C.35 : github.com/isocpp/CppCoreGuidelines/blob/master/…Araceli

© 2022 - 2024 — McMap. All rights reserved.