I find The rule of Zero as also mentioned on Peter Sommerlads Slides (p.32) very compelling.
Although, I seem to remember that there was a strict rule that one has to define the destructor virtual, if the class has virtual members and is actually derived.
struct Base {
virtual void drawYourself();
virtual ~Base() {}
};
struct Derived : public Base {
virtual void drawYourself();
};
The body of the destructor may even be empty (it only needs the entry in the vtbl).
I seem to remember that when use the hierarchy
int main() {
Base *obj = new Derived{};
obj->drawYourself(); // virtual call to Derived::drawYourself()
delete obj; // Derived::~Derived() _must_ be called
}
then it is important that delete obj
calls the correct destructor. Is it correct, that if I left out the destructor definition totally, it would not become virtual, and therefore the wrong d'tor would be called?
struct Base {
virtual void drawYourself();
// no virtual destructor!
};
This leads me to my final question:
- Is the "Rule Of Zero" also true in hierarchies with virtual methods
- or do I need to define the virtual destructor in these cases?
Edit: As I was reminded in an answer, my 1sr version of the question had the wrong assumptions. The relevant (virtual) destructor is in Base
, not Derived
. But my question holds: Do I need to declare (virtual) destructors at all?
delete
polymorphically. – Runesmith= default
ing special members does not violate the Ro0 in any way. The important part is, that you don't implement their functionality yourself and instead derive it from building blocks likeunique_ptr
andvector
, which handle a single responsibility. And tbh, even as you have it, without= default
, is fine for a destructor - since you don't manually do anything in it. Everything is still handled by the appropriate members' destructors. – Averroismstd::shared_ptr<Base>
, if constructed fromDerived*
(ormake_shared<Derived>
) will clean-up by callingDerived::~Derived()
and does not requireBase::~Base()
to be virtual. – Spermicideshared_ptr
(andunique_ptr
, too, I presume) do that. I know about custom deleters. Is that the way it does it? Yeah, must be. The constructor ofshared_ptr
sets its custom deleter by using the type it has been instantiated with. Hrmm. Correct? – Marriedstd::shared_ptr
. Instd::unique_ptr
you don't get that behavior, because the custom deleter is part of the type (i.e. allstd::unique_ptr<Base, ThisDeleterType>
will delete objects the same way). Sounique_ptr
custom deleters really are not useful for polymorphism. – Spermicide