Destructor for Dynamic Array in C++

Namita Chaudhary Nov 22, 2023
  1. Understanding Dynamic Arrays in C++
  2. Destructor for Dynamic Array in C++
  3. Example of Destructor in C++
  4. Delete Dynamic Array Using Destructor in C++
  5. Pitfalls and Best Practices
  6. Conclusion
Destructor for Dynamic Array in C++

While programming in any programming language, we often hear about constructors and destructors. Constructors are special member functions used to initialize the object of a class, whereas destructors are also special functions that are automatically called when an object is going to be destroyed.

In C++, a dynamic array, often referred to as a resizable array or a vector, is a versatile data structure that dynamically allocates memory to accommodate a varying number of elements. Understanding and implementing a destructor for such a dynamic array is crucial to managing memory properly and preventing memory leaks.

This article will discuss the destructor for dynamic arrays in C++ in detail.

Understanding Dynamic Arrays in C++

Dynamic arrays in C++ are typically implemented using pointers to a block of memory, which can be resized as needed to accommodate changing data sizes. The new and delete[] operators are used to allocate and deallocate memory for these arrays, respectively.

Here’s a simple example of a dynamic array implementation:

class DynamicArray {
 private:
  int* arr;
  int size;

 public:
  // Constructor
  DynamicArray(int initialSize) {
    size = initialSize;
    arr = new int[size];
  }

  // Destructor
  ~DynamicArray() { delete[] arr; }

  // Other methods for manipulation (add, remove, access elements, etc.)
};

The DynamicArray class manages a dynamically allocated array of integers. It uses a constructor to initialize the size of the array and dynamically allocate memory for it using new and a destructor to ensure that memory is properly deallocated using delete[] when the object is destroyed, preventing memory leaks.

Additional methods can be added to perform various operations on the array stored within this class.

The Role of Destructors

A destructor in C++ is a special member function that is automatically called when an object goes out of scope or is explicitly deleted. Its primary purpose is to release any resources (like memory, file handles, etc.) that the object might have acquired during its lifetime.

For a dynamic array, the destructor plays a crucial role in preventing memory leaks by deallocating the memory that was allocated using new. If the destructor is not properly implemented, the memory allocated for the dynamic array will not be freed when the object is destroyed, leading to memory leaks.

In the example provided earlier, the destructor ~DynamicArray() uses the delete[] operator to release the memory allocated for the dynamic array arr. This ensures that when an object of DynamicArray goes out of scope or is explicitly deleted, the memory used by the array is properly deallocated.

It’s essential to note that if the dynamic array contains elements that were themselves dynamically allocated (like objects created using new), the destructor should handle releasing memory for those elements as well. This may involve iterating through the array and deleting individual elements before deallocating the array itself.

Destructor for Dynamic Array in C++

Destructors are special member functions that have the same name as the class and are automatically invoked when an object is going to be destroyed.

The destructor function is the last function that is called when an object is destroyed. It cleans up the memory that the objects created by the constructor occupy.

However, both the constructor and destructor have the same name as that of the class, but there lies a difference between the two in terms of how they are written so that the compiler can differentiate them. The destructors are written using a negation symbol (~) followed by the class name and the constructors with just the class name.

Moreover, there can only be a single destructor for a class, but the constructors can be multiple.

Whenever an object is created in C++, it occupies memory in the heap section, and we use the new keyword to dynamically create that object of the class. Similarly, the delete keyword is used to delete the dynamically created object of the class.

Need for Destructor in C++

We need to delete the object to avoid any memory leaks. A memory leak occurs when the programmers forget to delete the memory in the heap that is not in use.

Because of this, the computer’s performance reduces as it reduces the amount of available memory. Moreover, if the objects are not explicitly deleted using the destructors, the program will crash during the runtime.

Example of Destructor in C++

In this example, we will be dynamically creating the object of a class using the new operator and explicitly deleting it using the delete keyword in C++.

Below is an example of how to delete the object of a class using the delete operator in C++.

#include <iostream>
using namespace std;

class Employee {
 public:
  Employee() { cout << "Constructor of Employee class was called!\n"; }
  ~Employee() { cout << "Destructor of Employee class was called!\n"; }
  void work() { cout << "Still Working!\n"; }
};
int main() {
  Employee* emp = new Employee();
  emp->work();
  delete emp;

  return 0;
}

Output:

Constructor of Employee class was called!
Still Working!
Destructor of Employee class was called!

In the above example, we have made a class Employee with a constructor, destructor, and a work function containing the appropriate message about their actions.

In the main function, we have created the object of the class emp using the new keyword and have called the work() function with it. After which, we just used the delete operator and the object name emp to delete the same.

Delete Dynamic Array Using Destructor in C++

Until now, we have seen how to delete a single object of a class using the delete keyword in C++. Now, let us see how to delete a dynamic array or an array of objects in C++.

In this example, we will create a dynamic array in C++ using the new keyword and then delete it using the delete operator.

However, one thing to remember while deleting a dynamic array in C++ is that we have to use the delete [] operator for doing so and not just delete. Therefore, the delete operator is used to delete a single object of a class, whereas to delete a dynamic array or an array of objects, we have to use the delete [] operator in C++.

Now, let us understand it with the help of a code example.

#include <iostream>
using namespace std;
class Employee {
 public:
  Employee() { cout << "Constructor of Employee class was called!\n"; }
  ~Employee() { cout << "Destructor of Employee class was called!\n"; }
  void work() { cout << "Still working!\n"; }
};
int main() {
  Employee* emp = new Employee[3];
  emp[0].work();
  emp[1].work();
  emp[2].work();

  delete[] emp;

  return 0;
}

Output:

Constructor of Employee class was called!
Constructor of Employee class was called!
Constructor of Employee class was called!
Still working!
Still working!
Still working!
Destructor of Employee class was called!
Destructor of Employee class was called!
Destructor of Employee class was called!

In this code example, we have a similar code as the previous example, but this time, we have created three Employee objects and deleted them using the delete [] operator in C++.

However, if we use the delete operator instead of the delete [], the program crashes during runtime. Let us also see an example of that to understand the deletion of the dynamic array in C++ more clearly.

#include <iostream>
using namespace std;
class Employee {
 public:
  Employee() { cout << "Constructor of Employee class was called!\n"; }
  ~Employee() { cout << "Destructor of Employee class was called!\n"; }
  void work() { cout << "Still working!\n"; }
};
int main() {
  Employee* emp = new Employee[3];
  emp[0].work();
  emp[1].work();
  emp[2].work();

  delete emp;

  return 0;
}

Output:

Error in `./example1.cpp': munmap_chunk(): invalid pointer: 0x000000000117f018 ***
timeout: the monitored command dumped core
/bin/bash: line 1:    33 Aborted                 timeout 15s ./0f6c05b9-ee09-44c3-acee-8ad8a882ac5e < 0f6c05b9-ee09-44c3-acee-8ad8a882ac5e.in

Constructor of Employee class was called!
Constructor of Employee class was called!
Constructor of Employee class was called!
Still working!
Still working!
Still working!
Destructor of Employee class was called!

Therefore, as you can see in the above output, the constructors and the function work have been called for all three objects, but the destructor has only been called once for a single object, after which the program crashed.

Pitfalls and Best Practices

When dealing with destructors for dynamic arrays, several pitfalls must be avoided:

  1. Double Deletion: Ensure that the memory deallocation occurs only once. Deleting the same memory block multiple times can lead to runtime errors.
  2. Memory Leak Prevention: If the dynamic array contains pointers to allocated memory, those pointers should be properly managed within the destructor to avoid memory leaks.
  3. Copy and Move Constructors/Assignment Operators: When implementing these functions for your class, ensure proper memory allocation and deallocation to avoid shallow copying issues that might impact the destructor’s functionality.

Conclusion

In conclusion, understanding the role of constructors and destructors in managing dynamic arrays in C++ is essential for effective memory management and preventing memory leaks. Constructors initialize the dynamic array, while destructors ensure proper deallocation of memory when the object goes out of scope.

The destructor for a dynamic array is crucial as it releases the memory allocated using new, preventing memory leaks. It’s vital to implement the destructor correctly, especially if the array contains dynamically allocated elements, to handle their deallocation as well.

Remembering to use delete[] for dynamic arrays and avoiding double deletion is crucial for proper memory management. Additionally, when implementing copy and move constructors or assignment operators, ensure they handle memory allocation and deallocation correctly to avoid issues impacting the destructor’s functionality.

By understanding and implementing proper memory management techniques, programmers can ensure efficient and reliable handling of dynamic arrays in C++, enhancing program stability and performance.

Related Article - C++ Array

Related Article - C++ Destructor