Does delete on a pointer to a subclass call the base class destructor?
Asked Answered
P

11

169

I have an class A which uses a heap memory allocation for one of its fields. Class A is instantiated and stored as a pointer field in another class (class B.

When I'm done with an object of class B, I call delete, which I assume calls the destructor... But does this call the destructor of class A as well?

Edit:

From the answers, I take that (please edit if incorrect):

  1. delete of an instance of B calls B::~B();
  2. which calls A::~A();
  3. A::~A should explicitly delete all heap-allocated member variables of the A object;
  4. Finally the memory block storing said instance of class B is returned to the heap - when new was used, it first allocated a block of memory on heap, then invoked constructors to initialize it, now after all destructors have been invoked to finalize the object the block where the object resided is returned to the heap.
Pears answered 24/3, 2009 at 14:30 Comment(0)
S
187

The destructor of A will run when its lifetime is over. If you want its memory to be freed and the destructor run, you have to delete it if it was allocated on the heap. If it was allocated on the stack this happens automatically (i.e. when it goes out of scope; see RAII). If it is a member of a class (not a pointer, but a full member), then this will happen when the containing object is destroyed.

class A
{
    char *someHeapMemory;
public:
    A() : someHeapMemory(new char[1000]) {}
    ~A() { delete[] someHeapMemory; }
};

class B
{
    A* APtr;
public:
    B() : APtr(new A()) {}
    ~B() { delete APtr; }
};

class C
{
    A Amember;
public:
    C() : Amember() {}
    ~C() {} // A is freed / destructed automatically.
};

int main()
{
    B* BPtr = new B();
    delete BPtr; // Calls ~B() which calls ~A() 
    C *CPtr = new C();
    delete CPtr;
    B b;
    C c;
} // b and c are freed/destructed automatically

In the above example, every delete and delete[] is needed. And no delete is needed (or indeed able to be used) where I did not use it.

auto_ptr, unique_ptr and shared_ptr etc... are great for making this lifetime management much easier:

class A
{
    shared_array<char> someHeapMemory;
public:
    A() : someHeapMemory(new char[1000]) {}
    ~A() { } // someHeapMemory is delete[]d automatically
};

class B
{
    shared_ptr<A> APtr;
public:
    B() : APtr(new A()) {}
    ~B() {  } // APtr is deleted automatically
};

int main()
{
    shared_ptr<B> BPtr = new B();
} // BPtr is deleted automatically
Schlosser answered 24/3, 2009 at 14:32 Comment(4)
I wonder if destructor is called when you free the memory only partially (eg. using wrong pointer)Orpington
Pointer is just a number. You can even accidentally use ++ operator on it. So I wonder if pointer that points in the middle of the class data still has the effect.Orpington
@TomášZato: If you call delete on a random pointer, then you're screwed. There's never a good reason to be doing that. In fact, if you're manually calling delete anywhere other than a smart-pointer destructor, then you probably want to take a second look at why you aren't using a smart pointer, or some other object manager.Schlosser
shared_array is from boost only, yes?Archimedes
C
33

When you call delete on a pointer allocated by new, the destructor of the object pointed to will be called.

A * p = new A;

delete p;    // A:~A() called for you on obkect pointed to by p
Coleman answered 24/3, 2009 at 14:36 Comment(0)
M
22

It is named "destructor", not "deconstructor".

Inside the destructor of each class, you have to delete all other member variables that have been allocated with new.

edit: To clarify:

Say you have

struct A {}

class B {
    A *a;
public:
    B () : a (new A) {}
    ~B() { delete a; }
};

class C {
    A *a;
public:
    C () : a (new A) {}        
};

int main () {
    delete new B;
    delete new C;
}

Allocating an instance of B and then deleting is clean, because what B allocates internally will also be deleted in the destructor.

But instances of class C will leak memory, because it allocates an instance of A which it does not release (in this case C does not even have a destructor).

Mallen answered 24/3, 2009 at 14:32 Comment(0)
H
6

If you have a usual pointer (A*) then the destructor will not be called (and memory for A instance will not be freed either) unless you do delete explicitly in B's destructor. If you want automatic destruction look at smart pointers like auto_ptr.

Hoang answered 24/3, 2009 at 14:34 Comment(0)
E
5

You should delete A yourself in the destructor of B.

Envenom answered 24/3, 2009 at 14:33 Comment(0)
H
4
class B
{
public:
    B()
    {
       p = new int[1024];  
    }
    virtual ~B()
    {
        cout<<"B destructor"<<endl;
        //p will not be deleted EVER unless you do it manually.
    }
    int *p;
};


class D : public B
{
public:
    virtual ~D()
    {
        cout<<"D destructor"<<endl;
    }
};

When you do:

B *pD = new D();
delete pD;

The destructor will be called only if your base class has the virtual keyword.

Then if you did not have a virtual destructor only ~B() would be called. But since you have a virtual destructor, first ~D() will be called, then ~B().

No members of B or D allocated on the heap will be deallocated unless you explicitly delete them. And deleting them will call their destructor as well.

Highspirited answered 24/3, 2009 at 14:34 Comment(0)
A
2

I was wondering why my class' destructor was not called. The reason was that I had forgot to include definition of that class (#include "class.h"). I only had a declaration like "class A;" and the compiler was happy with it and let me call "delete".

Akers answered 17/8, 2017 at 12:29 Comment(2)
Increase compiler warning levelPhilibeg
Very interesting answer! I was struggling with this for a while and you just saved me!Mihrab
T
1

You have something like

class B
{
   A * a;
}
B * b = new B;
b->a = new A;

If you then call delete b;, nothing happens to a, and you have a memory leak. Trying to remember to delete b->a; is not a good solution, but there are a couple of others.

B::~B() {delete a;}

This is a destructor for B that will delete a. (If a is 0, that delete does nothing. If a is not 0 but doesn't point to memory from new, you get heap corruption.)

auto_ptr<A> a;
...
b->a.reset(new A);

This way you don't have a as a pointer, but rather an auto_ptr<> (shared_ptr<> will do as well, or other smart pointers), and it is automatically deleted when b is.

Either of these ways works well, and I've used both.

Tryma answered 24/3, 2009 at 15:0 Comment(0)
S
0

No. the pointer will be deleted. You should call the delete on A explicit in the destructor of B.

Saltant answered 24/3, 2009 at 14:32 Comment(1)
I am doing this, my question was is the destructor called?Pears
E
0

The destructor for the object of class A will only be called if delete is called for that object. Make sure to delete that pointer in the destructor of class B.

For a little more information on what happens when delete is called on an object, see: http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.9

Elasticity answered 24/3, 2009 at 14:35 Comment(0)
B
0

no it will not call destructor for class A, you should call it explicitly (like PoweRoy told), delete line 'delete ptr;' in example to compare ...

  #include <iostream>

  class A
  {
     public:
        A(){};
        ~A();
  };

  A::~A()
  {
     std::cout << "Destructor of A" << std::endl;
  }

  class B
  {
     public:
        B(){ptr = new A();};
        ~B();
     private:
        A* ptr;
  };

  B::~B()
  {
     delete ptr;
     std::cout << "Destructor of B" << std::endl;
  }

  int main()
  {
     B* b = new B();
     delete b;
     return 0;
  }
Blaseio answered 24/3, 2009 at 14:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.