0
class A { 
....
};

class B: public A {
int x;
...
};

class C: public A{
A * ptr;
.....
};

class D : public A {
A* ptr1;
A* ptr2;
....
};

Note: I made all the constructors for B,C,D just didn't include them in there. So A (with no fields) is the super class and I have 3 subclasses (B,C and D) each with different fields.

A is an abstract class and its mostly chaining of Class (B,C,D)

So like I might have a situation like

B *x = new B {5};
B *x2 = new B {5}
D * y = new D{x,x2);

So when I do delete y; I want to make it chain destruct the 2 pointers of its two fields which are (B objects). How would I make the destructor for class D then chain destruct?

Like the example I show is really simple but other examples have more and more layers. I want to make sure that everything is deleted so no memory leaks occur.

Should my dtor for Class D look like this ?

~D(){
delete ptr1;
delete ptr2;
}

and for the case of class C would I just do this?

~C(){
    delete ptr;
    }

Because I did this and it doesnt work I get memory leaks so whats wrong?

  • 3
    Are you declaring your destructor as virtual? – Falmarri Jul 07 '16 at 22:12
  • for class A no. I thought i could override if I made ones in the subclass @Falmarri – Chi Long Hua Jul 07 '16 at 22:31
  • Should it make Class A destructor pure virtual and do I don't really need to make a destruct for Class B, it can just use its default one right? – Chi Long Hua Jul 07 '16 at 22:45
  • Standard says that if you're deleting by `base` pointer (pointing to `derived `object), `base` class should have `virtual` destructor, it doesn't matter if in `derived` you're doing something useful within it. – PcAF Jul 07 '16 at 23:29
  • I misclicked wrong answer, [this](http://stackoverflow.com/questions/2065938/virtual-destructor-is-it-required-when-not-dynamically-allocated-memory) is what you're looking for: – PcAF Jul 07 '16 at 23:33

1 Answers1

0

I assume your question is mistaken since you say it's a chain of inheritance but at time of writing B, C and D are inhereting directly from A.

When you do new D what happens is you have a composite object consisting of A, B, C and D - they are constructed in inheritance order.

*y = {
    // B starts
    int x;
    // C starts
    A * ptr;
    // D starts
    A * ptr1;
    A * ptr2;
};

Note that destructors will be called in reverse order, D first then C and so forth, to clean up the memory in reverse order (to deal with dependencies on superclass). However this depends on what sort of object you are deleting.

If we did this:

D * y = new D;
A * x = y;
delete x;

we have effectively treated y as an A object, meaning we are limited to what an A object knows about and can do so long as we're using x. If we delete using x, we are going to call ~A() rather than ~D(). This is why in this situation the destructors need to be virtual, which allows virtual ~A() to call ~D(), which will eventually call ~A() again (the real one not the virtual despatch).

Regardless of whether you are or are not using polymorphism / upcasting, your intuition is correct - ~D() should only clean up memory that D objects introduced to the class (ptr1 and ptr2), likewise for ~C() (only ptr).

The leak would be because of object slicing happening somewhere. For example (if you forced this to compile), this is worse than the above example because the object data won't be copied (as oppose to the structure definition being incomplete relative to the sort of object being referred to):

D d;
C * c = d; // not too bad, we can't refer to D-specific things.
C c2 = d; // bad, c2 is copied from D up to C superclass and no further.

Be very careful that you only pass the pointers / references to objects that may need to hold derived types, and where you do make sure you use virtual destructors. Otherwise what you're doing is correct, letting each class's destructor clean up just for that class.

Xeren Narcy
  • 875
  • 5
  • 15