9

Please consider the following:

class base{
    base();
    ~base();
}:

class derived : public base{

};

Does a base class destructor get automatically invoked when a derived object is destructed when the derived class has no destructor defined?

Otherwise, if I DO have a destructor in the derived class too, do I have to call the base class destructor explicitly?

class base{
    base();
    ~base();
}:

class derived : public base{
     derived();
     ~derived{
           base::~base(); //do I need this?
     }
};
AudioDroid
  • 2,292
  • 2
  • 20
  • 31
Heisenbug
  • 38,762
  • 28
  • 132
  • 190
  • 3
    No you don't need to do that - it's automatic – Erik Apr 05 '11 at 12:00
  • 1
    Note that you could answer this by simple experiment, by printing something out in the base destructor. – Beta Apr 05 '11 at 12:12
  • 1
    @Beta: you are right. But i preferred having a complete explanation of the subject. In fact now i realized that i should declare virtual my destructors in the base class. If I simply tried with a print statement i wouldn't realize that because actually i'm not calling any destructor on a base class reference. – Heisenbug Apr 05 '11 at 12:22

4 Answers4

15

The base class destructor is automatically invoked in this case; you do not need to call it.

However, note that when destroying an object through delete on a base class pointer and the destructor is not virtual, the result is going to be undefined behavior (although you might not get a crash).

Always declare the destructor as virtual in any class which is meant to be derived from. If the base class does not need to have a destructor, include a virtual one anyway with an empty body.

There is an exception to the above rule for an edge case: if your derived classes do not need to support polymorphic destruction, then the destructor does not need to be virtual. In this case it would be correct to make it protected instead; more details here, but be advised that this rarely occurs in practice.

Jon
  • 428,835
  • 81
  • 738
  • 806
  • 1
    The **base class** destructor is still executed. The **derived** isn't – Erik Apr 05 '11 at 12:03
  • That's kind of a weird statement, if you call delete on base class, only the base class destructor is invoked (if not virtual), so the base class destructor is invoked always :-D – Šimon Tóth Apr 05 '11 at 12:03
  • "The wrong destructor will be called" is inaccurate. In fact, only the base destructor will be called, and UB will have been invoked. – Lightness Races in Orbit Apr 05 '11 at 12:04
  • @Erik, @Let_Me_Be: Writing for speed is on the expense of correctness. I corrected that as soon as I read it again. – Jon Apr 05 '11 at 12:05
  • @Jon: I can still read it as "the wrong destructor will be called" – Alok Save Apr 05 '11 at 12:11
  • @Jon : "Always declare the destructor as virtual in any class which is meant to be derived from". Do I need to do the same for constructors? – Heisenbug Apr 05 '11 at 12:13
  • @Overbose: Constructors cannot be virtual. – Alok Save Apr 05 '11 at 12:15
  • @TomalakGeret'kal, @Als: Further edits and corrections made. Thank you for the comments and your patience, I can't multitask all that fast :) – Jon Apr 05 '11 at 12:18
  • 2
    @Jon: Ugh, no, do not make destructors `virtual` just for the sake of inheritance. Only if you intend to use polymorphism! Otherwise you're just forcing virtual dispatch for potentially no reason. You do talk about this, but as a rare "edge case".. and a protected destructor is only useful for an pure virtual base. KISS! – Lightness Races in Orbit Apr 05 '11 at 12:21
  • @TomalakGeret'kal: Unless you take explicit steps to *prevent* the class from being used polymorphically, I believe the destructor *must* be virtual (I would consider a design that bases correct behavior on a "DO NOT USE THIS POLYMORPHICALLY" comment to be flawed). – Jon Apr 05 '11 at 12:36
  • @Jon: :) We're verging into heavily subjective territory now, I guess. I prefer not to have heavy polymorphic classes running about all over my damned code, when I never use polymorphism on them. – Lightness Races in Orbit Apr 05 '11 at 12:40
  • @Erik: "The base class destructor is still executed" - behavior is undefined (5.3.5/3). Perhaps on your implementation the base class destructor is executed. Perhaps on mine it isn't. – Steve Jessop Apr 05 '11 at 12:43
  • @Jon: perhaps flawed, but certainly it is idiomatic C++ (almost all standard classes have public non-virtual destructors). I think a design that inherits from a C++ class that isn't explicitly documented to be suitable for inheritance is more severely flawed. Documenting "do not delete polymorphically" is a bit limiting, but if for example you want a POD class, then you *can't* give it a virtual or a protected destructor. Documentation is all that's left, so if users are determined to inherit from it and delete through pointer-to-base then it's their own stupidity they'll suffer for. – Steve Jessop Apr 05 '11 at 12:48
  • @SteveJessop: Agreed. But keep in mind that it does read "any class which is meant to be derived from". That would rule out POD and really a *lot* of other cases which would better be modeled by composition instead of inheritance, like the inheriting from class not supposed to be inherited from case that you mention. – Jon Apr 05 '11 at 12:52
  • @Jon: the "explicit step" to prevent polymorphic destruction is simply to define a protected destructor. (This assumes that the base class is abstract, but inheriting from a non-abstract class would be rather odd in my opinion). – Mike Seymour Apr 05 '11 at 12:54
  • @Jon: it all falls out nicely if you follow the advice that non-abstract classes must be leaf classes. Then you wouldn't inherit from a POD class, since of course it's not abstract. Your "edge cases" include things like CRTP and composition through private inheritance, where a class *is* intended (or at least suitable) for use as a base but clearly is *not* suitable for polymorphic deletion. How rare that is depends on coding style - you don't *have* to use dynamic polymorphism at all, and even when you do, if the dtor is non-virtual `shared_ptr` can still safely delete derived objects. – Steve Jessop Apr 05 '11 at 12:59
  • ... which is not to say that I advise leaving the dtor non-virtual just because `shared_ptr` can cope, just that it's available as a workaround. – Steve Jessop Apr 05 '11 at 13:02
  • @Jon why "undefined behavior"? – Prashant Bhanarkar Aug 22 '16 at 06:43
2

Does a base class destructor is automatically invoked when a derived object is destructed and the derived class has no destructor defined?
Yes, the Base class destructor is automatically invoked after the Derived class Destructor, irrespective of Derived class destructor being explicitly defined or not.

Otherwise, if I have a destructor in the derived class too, do I need to call explicitly base class destructor too?
No, You don't need to. There will not be any scenario in C++, where one has to explicitly invoke a destructor except while using placement new.

Alok Save
  • 202,538
  • 53
  • 430
  • 533
1

No, base destructors are invoked automatically in this case, in much the same way that base constructors are can be invoked automatically.

Note, though, that if you are using polymorphism and destroying through a base pointer, you should make sure that the destructor is virtual otherwise this will break.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
1

You should never invoke a base class destructor from a derived class destructor.

The reason is base class destructor will be then called automatically for the second time and writing destructors in such way that this doesn't cause problem is problematic - see this question.

Community
  • 1
  • 1
sharptooth
  • 167,383
  • 100
  • 513
  • 979