0

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.

  • 1
    Related: http://www.gotw.ca/publications/mill18.htm – SingerOfTheFall Nov 03 '16 at 09:10
  • NO. What the class itself does or contains internally is utterly irrelevant. The only criterion is how it is used. If a derived class object is to be deleted through a base pointer, the base class must have a virtual destructor. Nothing more, nothing less. – n. m. could be an AI Nov 03 '16 at 09:38
  • But developer can't be sure about usage of base class pointer as pointer to derived class, that other developer will make, and use in such way. So, again, base class developer should declare d-r as virtual. Or there is chance of UB. – Ярик Зюлин Nov 03 '16 at 09:44
  • I don't hear too many stories about developers doing it with `std::vector`, or indeed 90%+ of the standard library classes. When it happens once in a while, a developer quickly gets slapped on the wrist and learns to never do it again. Class authors should document intended usage. They need not provide safeguards against non-intended usage. – n. m. could be an AI Nov 03 '16 at 10:05
  • Ok, I got it, thanks! – Ярик Зюлин Nov 03 '16 at 10:07

1 Answers1

3

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

Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365
  • Ok thanks, I see now. So, my suggestion mainly was correct, the developer decides this basing on hope that a user is a good user, or not – Ярик Зюлин Nov 03 '16 at 09:48
  • @ЯрикЗюлин or conversely, the user should investigate whether the class has a virtual destructor, before deciding to try to derive from it and use a base class pointer (which is probably a bad idea anyway, there is no reason to do this when there are no virtual functions) – M.M Nov 03 '16 at 09:51
  • And if designer uses base class pointer in deletion, but has non-virtual d-r - this implicitly says, that this base class is not supposed to be used as base class at all, yes? – Ярик Зюлин Nov 03 '16 at 09:54
  • @ЯрикЗюлин if the designer does not include virtual destructor, then generally yes, it was not intended to derive from. For example `std::string` and the other standard containers. Not sure what you mean about base class pointer there – M.M Nov 03 '16 at 09:58
  • class A{ class A* buddy; A(class A*new_buddy){buddy = new_buddy;} ~A(){delete buddy;} }; class B : A {}; A val = A (new B() ); there designer supposed, that buddy can be only of A, but user tries to give B as buddy – Ярик Зюлин Nov 03 '16 at 10:05
  • Yep, class supposed to have default c-r with zero arg as new_buddy, to make it compilable – Ярик Зюлин Nov 03 '16 at 10:11
  • In most cases, objects will be destroyed by the same entity that created them. Since that entity must have known the type of the object it was creating, it should have no problem ensuring that it destroys the same type. The only problematic situation occurs if the code that creates an object passes it to other code that needs to delete it but knows it only as the base type. – supercat Nov 03 '16 at 22:27