All About Destructors in C++

Roshan Alwis
Tech Vision
Published in
6 min readSep 11, 2017

Introduction

If you have programmed in C++ with OOP concepts, you all might know that C++ has this strange feature called “Destructor”. We simply state that destructor is the inverse of the constructor. Which is to deallocate assigned memory and do other cleanup related to a class object when the object is destroyed.
In this article, we are planning to discuss how to work with destructors properly including declaration rules, why we need it? When we need it?

How to declare a destructor?

We can declare a destructor by adding a tide (~) as prefix to its class name. for example ~Test() is the destructor for class Test.

When it comes to declaration a destructor, we need to follow some rules.

  1. Destructors do not accept arguments. So, we cannot overload it as a constructor. Because we do not need to deallocate memory in different ways (partially/fully). We have to fully deallocate memory what we have allocated. So, there is one destructor per class.
  2. Destructors do not have a return type. This condition is same as to a constructor. Because we do not need to explicitly check for the success of every single object. In worst case scenario it will throw an exception.
  3. Cannot return a value using return statement.
  4. Cannot be declared as const, volatile or static. But can be invoked at destruction of a object declared as const, volatile or static.
  5. Can be declared as virtual. Virtual destructors will allow to destroy objects without knowing their type. (We will discuss on this later in the article).

Why we need it?

Since C++ does not include a garbage collector like in other high-level languages (Java/C#), sometimes we have to explicitly deallocate the memory what we have assigned. So, programmers have to do this dirty job manually. Otherwise, this could be lead to a memory leak.

What is a memory leak?

If we continuously allocate memory for a particular object without releasing that memory after completing its task, that memory can not be used in future. Because, although object has completed its task, it is holding that memory because we have not released it properly. So, others cannot grab that memory for their executions.
This wasted memory can be started in few bytes but eventually, end up in megabytes or even more. This might slow down your application in execution when it finds hard to allocate memory or may be crashed as it failed to allocate enough memory for its execution.
So, destructor comes in handy to deallocate memory that it has allocated when the constructor was called.

When we need it?

We need to call the destructor if have allocated memory in heap. If we have allocated memory in stack we do not need to call it explicitly. Let’s look at the following example to get an idea about the order of execution.

Output would be like this,

Output

Here we do not want to call the destructor explicitly because we have created the object in the stack, not in heap. So, after object goes out of scope destructor will call automatically.

What if we create the object in heap instead of stack?

int main(){
Test *a = new Test();
a->display();
}
Output

But in this scenario, you can see that it will not call the destructor automatically. So, we have to call it explicitly. Unless memory will not be released at the end of the scope of the object. We can call delete in order to invoke the destructor manually.

int main(){
Test *a = new Test();
a->display();
delete a;
}

For this example, we have not used any inside variable which allocates memory dynamically. We just wanted to observe whether the destructor is calling or not properly. Now, Let’s move little further with this.

In the above example, we dynamically allocate memory for student name and student marks. Normally we can use delete key word to deallocate the memory from an object pointer. Since we have stored marks in an array we have to deallocate memory for each object in the array and finally from the array pointer when the destructor is called. So, we have to call the keyword delete[].

Output

Now let’s look at virtual destructors.

What is a Virtual Destructor?

I think most of you have learned about polymorphism and inheritance which are two key elements in OOP paradigm. And you also should have an idea about the role of the virtual keyword in C++, which is, it let you achieve polymorphism, by selecting the most-derived override of a method at run-time.
When we have a derived class object pointed by a base class object, non-virtual destructor results in ambiguous behavior. To correct this situation, base class destructor needs to be defined in terms of virtual. Let’s compare the differences between two approaches using following example.

Here we have done a polymorphic deletion which means we are deleting an object at the base class level which is actually a derived class object. In this example, Animal is the base class of Dog class. We have a created an object of dog and then assigned that object pointer to a base class object pointer. What if we delete the base class object pointer?

Output

You can see that Dog destructor has not called at all, which can lead to a memory leak that we have discussed early in this article. Because Dog can have its own attributes as it is a derived class. So, that memory would not be released at this point.
This behavior can be differed according to the compiler. But, if you are meant to perform a polymorphic deletion there is a safe way to do it. We just need to declare the base class destructor as virtual. It will guarantee the invocation of the derived class destructor.

virtual ~Animal(){
cout << "Animal destructor" << endl;
}
Output

You can observe that all the destructors have been called hierarchically.

When to use it?

For base classes with polymorphic deletion.

Although we have a base class, that does not mean we have to declare the destructor as virtual all the time. But it guarantees to use hierarchical classes in a flexible manner without accidentally getting into an ambiguous state. Mostly when we try to invoke a derived class destructor using a base class pointer.

When not to use it?

  1. For a concrete class which doesn’t want to be inherited.
  2. For a base class without polymorphic deletion.

--

--

Roshan Alwis
Tech Vision

Software Engineer at Sysco Labs. (Computer Science & Engineering Graduand at University of Moratuwa)