Default destructor in subclasses of base class with a virtual destructor
Asked Answered
F

3

10

I have a base class A with a virtual destructor. A has descendants B and C which use the default destructor. Is it safe to delete an object of C through a pointer to A?

More specifically, consider this sample code:

class A {
 public:
      A(){};
      virtual ~A() {/* code here */};
 };
 class B: public A {
      B() {/* code....*/};
      /* NO DESTRUCTOR SPECIFIED */
   };
 class C: public B {/*same as above, no destructor */};
 class D: public B {/* same as above, no destructor*/}

The code to be run looks something like this:

A* getAPointer(void); /* a function returning a C or a D*/
A* aptr=getAPointer();
/* aptr is declared as A*, but points to either an object of class C 
  or class D*/
delete aptr;

Is the delete aptr safe? Does it do the right thing: if aptr points to an object of class C, the aptr first calls C's destructor, then B's destructor, and finally A's destructor ?

Flat answered 20/1, 2018 at 12:43 Comment(0)
P
12

Is it safe to delete an object of C through a pointer to A?

Yes, it is totally safe as all the destructors in classes B, C and D will be implicitly virtual.

From:

15.4 Destructors [class.dtor]

10 A destructor can be declared virtual (13.3) or pure virtual (13.4); if any objects of that class or any derived class are created in the program, the destructor shall be defined. If a class has a base class with a virtual destructor, its destructor (whether user- or implicitly-declared) is virtual.

As A has a virtual destructor, then B, and C, D respectively, have virtual destructors and:

delete aptr;

works correctly.

Peak answered 20/1, 2018 at 12:45 Comment(0)
R
3

Yes, it's safe. Adding virtual to the destructors of your derived classes is redundant.

Consider how the mechanism works. When delete is used, the runtime needs to know with which destructor the destruction chain should begin. If the static type of the delete operand has a virtual destructor, then that's already sufficient for the runtime to know that it must take the extra trouble and inspect the dynamic type.

In your case, it finds that the dynamic type is C, so C::~C is called. C::~C automatically leads to B::~B and that one automatically leads to A::~A.

A requirement for C's (or B's) destructor to be virtual would be pointless. After all, the runtime has to find out the dynamic C type anyway if A::~A is virtual. At that point, it doesn't care whether C::~C is virtual or not. What difference would it make?

Raymonderaymonds answered 20/1, 2018 at 13:6 Comment(1)
With that description, what is not apparent is that it also works fine if you have a pointer declared as the "middle" type B, and the actual concrete runtime type is C. AFAIK, a derived class cannot "devirtualise" something that was virtual in a base class.Holiday
U
0

Is it safe to delete an object of C through a pointer to A?

Yes. Since A's destructor is virtual, C's destructor will be called. This is simply due to how dynamic dispatch works.

Unprincipled answered 20/1, 2018 at 12:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.