Destructor

Destructors are the opposite of Constructors. They’re a special member function that is executed automatically when an object is destroyed.

  • Used to deallocate the memory that has been allocated for the object by the constructor

In C++

The destructor is the same name as the class, with a ~ in front.

Object destruction sequence (this is the inverse of Constructor order)

  1. Destructor body runs
  2. Object fields have their destructors run in reverse declaration order
  3. Superclass destructor runs
  4. Space is reclaimed

Use Virtual Destructors!!

Destructors are usually declared as Virtual Methods though technically they can’t be overridden.

virtual ~Balloon() {
	...
};

Always use virtual

Unless you are sure a class will never be subclassed, then always declare your destructors as virtual.

If you are sure that your class will never be subclassed, enforce it via the final keyword.

Motivation through example

The motivation for this was seen in CS247, through the following example:

class X {
    int* a;
 
public:
    X(int n): a{new int[n]}{}
    ~X() { delete[] a; }
};
 
class Y: public X{
    int* b;
 
public: 
    Y(int n, int m): b{new int[m]}{}
    ~Y() { delete[] b; }
};
 
X x{5};
X* px = new X{5};
Y y{5,10};
Y* py = new Y{5,10};
X* pxy = new Y{5,10};
delete px; delete py; delete pxy;

Which of these leaks memory?

Object destruction sequence:

  1. Destructor body runs
  2. Object fields have their destructors run in reverse declaration order
  3. Superclass destructor runs
  4. Space is reclaimed

Because the destructor is non-virtual, for pxy, we invoke ~X, not the ~Y, so this array b is leaked.

  • This is confusing, see Virtual Method
  • If we do declare it the superclass destructor as virtual, it knows to look for the derived class’s implementation of the destructor. Thus, it would first calls ~Y (derived class’s destructor), and then it ALSO calls ~X (superclass destructor).
    • in this case, it doesn’t matter that the names of the destructors are different. Both derived and parent destructors will be called

Solution: declare virtual ~X(), so delete pxy calls ~Y().

Therefore, unless you are sure a class will never be subclassed, then ALWAYS declare your destructors as virtual.

If you are sure, enforce it via the final keyword.

class X final {
	... // Program won't compile if anyone tries to subclass X
}

Why are destructors declared as virtual, but not constructors?

I think it is because of the way we are achieving Polymorphism. Consider something like Base* b = new Derived{}. Only the Derived constructor gets called here.

Also some better explanations in StackOverflow and Quora.

When does a destructor get called?

When does a destructor get called? When the variable goes out of scope.

What if there are multiple destructors to call?

Destructors are called in reverse order of their creation.

In this example (from Observer Pattern), the destructor for wario gets called first, followed by joe, and finally elon.

int main() {
  Tweeter elon{"elon.txt"};
  Follower joe{&elon, "joe"};
  Follower wario{&elon, "wario"};
 
  while (elon.tweet()) {
    elon.notifyObservers();
  }
}

In Python

def __del__(self):
  # body of destructor