Introduction to C++ | Destructor

C++ Destructor

A destructor in C++ is a special member function that is automatically invoked when an object goes out of scope or is explicitly deleted. The purpose of a destructor is to clean up resources acquired by an object during its lifetime, such as releasing dynamically allocated memory or closing file handles. A destructor ensures proper cleanup and helps prevent memory leaks and other resource management issues.

What is a Destructor?

A destructor has the following characteristics:

The main function of a destructor is to release resources such as memory or file handles that were acquired by the object during its lifetime.

Syntax of Destructor

The syntax for declaring a destructor is as follows:

Syntax of Destructor


        class ClassName {
        public:
            ~ClassName() {
                // Destructor body: Cleanup code here
            }
        };
                    

Example of Destructor

Here’s a simple example of how a destructor works in C++:

Code Example: Destructor


        #include <iostream>
        using namespace std;
        
        class Car {
        public:
            string brand;
            int year;
        
            // Constructor to initialize brand and year
            Car(string b, int y) {
                brand = b;
                year = y;
                cout << "Car " << brand << " created!" << endl;
            }
        
            // Destructor to clean up resources
            ~Car() {
                cout << "Car " << brand << " destroyed!" << endl;
            }
        
            void displayDetails() {
                cout << "Brand: " << brand << ", Year: " << year << endl;
            }
        };
        
        int main() {
            // Creating an object of class Car
            Car myCar("Toyota", 2020);
            myCar.displayDetails();  // Output: Brand: Toyota, Year: 2020
        
            return 0;  // Destructor is called when myCar goes out of scope
        }
                    

Output:

Car Toyota created!
Brand: Toyota, Year: 2020
Car Toyota destroyed!

When is a Destructor Called?

A destructor is called in the following situations:

For example, when a function exits, any local variables in the function will go out of scope, and their destructors will be automatically called.

Example of Destructor with Dynamic Memory Allocation

If a class allocates memory dynamically, the destructor is responsible for deallocating that memory to avoid memory leaks. Here's an example of a destructor that handles dynamic memory allocation:

Code Example: Destructor with Dynamic Memory


        #include <iostream>
        using namespace std;
        
        class Car {
        public:
            string* brand;
            int year;
        
            // Constructor with dynamic memory allocation
            Car(string b, int y) {
                brand = new string(b);  // Allocate memory dynamically
                year = y;
            }
        
            // Destructor to free dynamically allocated memory
            ~Car() {
                delete brand;  // Free the allocated memory
            }
        
            void displayDetails() {
                cout << "Brand: " << *brand << ", Year: " << year << endl;
            }
        };
        
        int main() {
            // Creating an object of class Car
            Car myCar("Honda", 2022);
            myCar.displayDetails();  // Output: Brand: Honda, Year: 2022
        
            return 0;  // Destructor is called here to free dynamically allocated memory
        }
                    

Output:

Brand: Honda, Year: 2022

Destructor in Inheritance

In C++, destructors in derived classes are automatically called when a base class object is destroyed. However, if the base class has a destructor that is not virtual, it may not properly invoke the destructor of the derived class, which can lead to resource leaks. To ensure proper cleanup in case of inheritance, it's good practice to declare the destructor in the base class as virtual.

Example of Virtual Destructor in Inheritance

Here’s an example where a virtual destructor ensures proper cleanup in a class hierarchy:

Code Example: Virtual Destructor


        #include <iostream>
        using namespace std;
        
        class Vehicle {
        public:
            virtual ~Vehicle() {  // Virtual destructor
                cout << "Vehicle destroyed!" << endl;
            }
        };
        
        class Car : public Vehicle {
        public:
            ~Car() {
                cout << "Car destroyed!" << endl;
            }
        };
        
        int main() {
            Vehicle* vehicle = new Car();  // Create a Car object using base class pointer
            delete vehicle;  // Calls the destructor of Car, followed by Vehicle
        
            return 0;
        }
                    

Output:

Car destroyed!
Vehicle destroyed!

Pro Tip:

💡 Pro Tip

Always define destructors as virtual in base classes when dealing with inheritance. This ensures that the derived class’s destructor is called when an object is deleted through a base class pointer, preventing potential memory leaks and resource issues.