Destructor in C++: Syntax, Examples, Virtual Destructor, Working, Advantages & Constructor vs Destructor

Destructor in C++ Syntax, Examples, Virtual Destructor & Advantages

When working with classes and objects in C++, managing an object’s lifecycle is just as important as creating it. While constructors initialize an object when it is created, there must also be a mechanism to release the resources that the object acquires during its lifetime. This is where destructors in C++ become essential.

A destructor is a special member function that is automatically executed when an object is destroyed. Its primary responsibility is to perform cleanup tasks such as releasing dynamically allocated memory, closing files, terminating network connections, and freeing other system resources. By handling cleanup automatically, destructors help prevent memory leaks and ensure that applications remain efficient and reliable.

Understanding destructors is a fundamental part of learning Object-Oriented Programming (OOP) in C++. Whether you are developing desktop applications, embedded systems, IoT solutions, games, or enterprise software, proper resource management is crucial for building stable and maintainable applications.

In this article, you will learn:

  • What a destructor is in C++
  • Why destructors are important
  • How destructors work
  • Destructor syntax with examples
  • Order of constructor and destructor calls
  • Virtual destructors and their importance
  • Constructor vs Destructor comparison
  • Advantages and best practices
  • Common interview questions

By the end of this guide, you will have a clear understanding of how destructors complete the lifecycle of C++ objects and why they are an essential feature for effective memory and resource management.

  • A destructor is a special member function that is automatically called when an object is destroyed.
  • It has the same name as the class with a tilde (~) prefix, takes no arguments, and has no return type.
  • Destructors are primarily used to release resources such as dynamically allocated memory, open files, and network connections.
  • Every class can have only one destructor, and it cannot be overloaded.
  • Constructors execute when an object is created, while destructors execute when the object’s lifetime ends.
  • When multiple objects are created, constructors execute in creation order, while destructors execute in reverse order.
  • A virtual destructor ensures that both base and derived class destructors are called correctly when deleting an object through a base class pointer.
  • Using destructors helps prevent memory leaks, improves resource management, and makes C++ applications more reliable and maintainable.

1. What is a Destructor?

A destructor is a special member function of a class that is automatically called when an object of that class is destroyed. Its job is the exact opposite of a constructor’s — instead of setting things up, it cleans things up before the object’s memory is taken back.

A destructor has the same name as the class, preceded by a tilde (~), takes no arguments, has no return type, and cannot be overloaded. Every class has exactly one destructor, and the compiler calls it automatically—you never call it directly.

Syntax

class Student
{
public:
    ~Student()
    {
        // Cleanup code
    }
};

Key Characteristics of a Destructor

  • It has the same name as the class with a tilde (~) prefix.
  • It does not have a return type.
  • It does not accept any parameters.
  • A class can have only one destructor.
  • It cannot be overloaded.
  • It is called automatically by the compiler.
  • It is mainly used for releasing resources before the object is destroyed.

2. Why Do We Need a Destructor?

As programs become larger and more complex, objects often acquire resources during their lifetime. These resources may include dynamically allocated memory, open files, database connections, network sockets, or hardware devices. If these resources are not released properly, they continue occupying memory or system resources even after the object is no longer needed.

Destructors solve this problem by automatically performing cleanup when an object’s lifetime ends.

Some important reasons why destructors are needed include:

  • It releases resources an object was holding, such as dynamically allocated memory, open files, or network connections.
  • It prevents memory leaks by ensuring cleanup happens automatically, instead of relying on the programmer to remember it every time.
  • It guarantees cleanup runs even when an object goes out of scope unexpectedly, such as through an early return or an exception.
  • It allows a class to log, notify, or perform any final action right before an object disappears.
  • It pairs naturally with constructors, completing the full lifecycle of an object from setup to teardown.

Real-World Example

Imagine a program that opens a file for writing student records.

  • The constructor opens the file.
  • The program writes student data.
  • The destructor automatically closes the file.

Without the destructor, forgetting to close the file could lead to data corruption or resource leaks.

3. How Does a Destructor Work?

Whenever an object’s lifetime ends, the compiler automatically inserts a call to its destructor—you never write this call yourself.

The process happens in a fixed order:

  1. The object reaches the end of its scope, or is explicitly deleted (for objects created with new).
  2. The compiler automatically calls the class’s destructor on that object.
  3. The destructor’s body runs, releasing any resources the object was holding.
  4. The memory used by the object itself is then reclaimed.

In Short

A destructor runs automatically at the end of an object’s life, giving the class one last chance to clean up safely before the object is gone for good.

Object Lifecycle

Object Created
       ↓
Constructor Executes
       ↓
Object is Used
       ↓
Object Goes Out of Scope or delete is Called
       ↓
Destructor Executes
       ↓
Memory Released

This automatic execution makes destructors one of the most reliable mechanisms for resource management in C++. Developers do not need to manually invoke them, reducing the possibility of forgetting important cleanup operations.

4. Destructor in Action: A Simple Example

Understanding the theory behind destructors is important, but seeing them in action makes their behavior much clearer. In this example, a constructor displays a message when an object is created, while the destructor automatically displays another message when the object is destroyed.

The object is created inside the main() function. As soon as the program reaches the end of main(), the object goes out of scope, and the compiler automatically calls the destructor. Notice that there is no explicit function call to the destructor anywhere in the program.

Example

#include 
using namespace std;

class Student {
public:
    string name;

    // Constructor
    Student(string n) {
        name = n;
        cout << name << " object created." << endl;
    }

    // Destructor
    ~Student() {
        cout << name << " object destroyed." << endl;
    }
};

int main() {

    Student s1("Aditi");

    cout << "Inside main, using the object..." << endl;

    return 0;   // s1 goes out of scope here, destructor fires automatically
}

Output

Aditi object created.
Inside main, using the object...
Aditi object destroyed.

Explanation

Let’s understand what happens step by step:

Step 1: The object s1 is created.

Student s1("Aditi");

The constructor executes automatically and prints:

Aditi object created.

Step 2: The next statement executes.

cout << "Inside main, using the object..." << endl;

Output:

Inside main, using the object...

Step 3: The program reaches the end of main().

return 0;

At this point, s1 goes out of scope.

Step 4: The compiler automatically calls the destructor.

Output:

Aditi object destroyed.

Key Observation

You never wrote:

s1.~Student();

The compiler automatically invokes the destructor when the object’s lifetime ends. This automatic cleanup makes C++ programs safer and helps prevent resource leaks.

5. Order of Constructor and Destructor Calls

When multiple objects exist, C++ follows a predictable order:

  • Constructors run in the order objects are created.
  • Destructors run in the exact reverse order.
  • The last object created is the first object destroyed (LIFO – Last In, First Out).

This reverse-order destruction is extremely important because objects created later may depend on objects created earlier. Destroying them in reverse order ensures that dependent objects are cleaned up safely.

Example

#include 
using namespace std;

class Demo {
public:

    int id;

    Demo(int i) {
        id = i;
        cout << "Constructing object " << id << endl;
    }

    ~Demo() {
        cout << "Destroying object " << id << endl;
    }
};

int main() {

    Demo a(1);
    Demo b(2);
    Demo c(3);

    return 0;
}

Output

Constructing object 1
Constructing object 2
Constructing object 3
Destroying object 3
Destroying object 2
Destroying object 1

Explanation

The objects are created in this order:

a → b → c

Therefore, constructors execute as:

1
2
3

When main() ends, destruction happens in reverse order:

c → b → a

So the output becomes:

3
2
1

 

registor_now_P

Why Does C++ Follow Reverse Order?

Suppose object B uses resources owned by object A.

If A were destroyed first, B would still be trying to access resources that no longer exist, causing undefined behavior.

Destroying objects in reverse order guarantees that dependent objects are destroyed before the objects they rely on.

Real-World Example

Imagine three objects:

Database Connection
Student Repository
Student Application

Creation order:

Database Connection
↓

Student Repository
↓

Student Application

Destruction order:

Student Application
↓

Student Repository
↓

Database Connection

The application is destroyed first because it depends on the repository, and the repository is destroyed before the database connection it depends on.

 

6. What is a Virtual Destructor?

A virtual destructor is a destructor declared with the virtual keyword in a base class. It ensures that when an object is deleted using a base class pointer, both the derived class destructor and the base class destructor are executed correctly.

Without a virtual destructor, only the base class destructor is called, and the derived class destructor is skipped. This can leave dynamically allocated memory and other resources unreleased, leading to memory leaks and undefined behavior.

Virtual destructors are essential whenever a class is intended to be used as a base class in inheritance.

Example Without Virtual Destructor

#include 
using namespace std;

class Base
{
public:
    ~Base()
    {
        cout << "Base Destructor" << endl;
    }
};

class Derived : public Base
{
public:
    ~Derived()
    {
        cout << "Derived Destructor" << endl;
    }
};

int main()
{
    Base *ptr = new Derived();

    delete ptr;

    return 0;
}

Output

Base Destructor

Only the base class destructor executes.

The derived destructor is skipped.

If the derived class had allocated dynamic memory, that memory would never be released, resulting in a memory leak.

Explore Courses - Learn More

7. Constructor vs Destructor

Constructors and destructors are two special member functions in C++, but they serve opposite purposes. A constructor initializes an object when it is created, whereas a destructor performs cleanup before the object is destroyed.

Together, they manage the complete lifecycle of an object—from initialization to cleanup.

AspectConstructorDestructor
NameSame as the class nameSame as the class name with a ~ prefix
ArgumentsCan take argumentsTakes no arguments
Return TypeNo return typeNo return type
OverloadingCan be overloadedCannot be overloaded
Number per ClassMultiple constructors are allowedOnly one destructor is allowed
Called WhenObject is createdObject goes out of scope or is deleted
PurposeInitializes the objectReleases resources and performs cleanup
Automatic CallYesYes

Example

class Student
{
public:
    Student()
    {
        cout << "Constructor Called" << endl;
    }

    ~Student()
    {
        cout << "Destructor Called" << endl;
    }
};

Output

Constructor Called
Destructor Called

Key Differences

  • Constructors allocate or initialize resources, whereas destructors release them.
  • Constructors can have parameters, but destructors cannot.
  • A class may contain multiple constructors but only one destructor.
  • Constructors execute first, while destructors execute at the end of an object’s lifetime.
  • Both are called automatically by the compiler, reducing the chances of programming errors.

8. Advantages of Destructors

Destructors provide several important benefits that make C++ programs safer, cleaner, and easier to maintain.

1. Automatic Cleanup

Resources are released automatically without requiring the programmer to remember to free them manually.

2. Prevents Memory Leaks

Objects that allocate memory dynamically can safely release it before destruction.

Example:

delete[] arr;

Without a destructor, this memory may remain allocated until the program terminates.

3. Exception Safety

Even if an exception occurs or a function returns early, destructors are still executed for local objects.

This automatic cleanup prevents resource leaks during unexpected situations.

4. Better Resource Management

Destructors help manage resources such as:

  • Dynamic memory
  • Files
  • Database connections
  • Network sockets
  • Hardware devices

5. Predictable Object Lifecycle

Objects are always destroyed in reverse order of their creation.

This predictable behavior makes programs easier to understand and debug.

6. Safer Inheritance

Virtual destructors ensure that derived class resources are cleaned up correctly when deleting objects through base class pointers.

7. Cleaner Code

Without destructors, programmers would need to manually release resources throughout the application.

Destructors centralize cleanup logic inside the class, making the code easier to maintain.

Best Practices for Using Destructors in C++

Following these best practices helps write efficient and reliable C++ programs.

Release Every Resource You Acquire

If a class allocates memory using new, release it using delete or delete[] inside the destructor.

Close Open Files

Always close files before the object is destroyed.

file.close();

Release Network Resources

If your application opens sockets or network connections, release them in the destructor.

Prefer Smart Pointers

Modern C++ encourages using smart pointers such as:

  • unique_ptr
  • shared_ptr

They automatically manage memory and reduce the need for manual cleanup.

Keep Destructors Simple

A destructor should focus only on cleanup.

Avoid performing lengthy computations or complex business logic.

Never Throw Exceptions from a Destructor

Throwing exceptions inside a destructor can terminate the program unexpectedly, especially during stack unwinding.

Use Virtual Destructors in Base Classes

Whenever a class is intended for inheritance, declare its destructor as virtual.

virtual ~Base() {}

This is considered one of the most important best practices in object-oriented programming.

Real-World Applications of Destructors

Destructors are widely used in real software development.

File Handling

Automatically close files after reading or writing.

Database Applications

Close database connections when objects are destroyed.

Network Programming

Release sockets and communication channels.

Embedded Systems

Free hardware resources such as:

This is especially important in memory-constrained embedded devices.

IoT Applications

Disconnect MQTT clients, release sensor interfaces, and close communication ports automatically.

Game Development

Destroy textures, models, audio buffers, and graphics resources.

Operating Systems

Release kernel resources before processes terminate.

Enterprise Applications

Close APIs, release caches, and terminate service connections.

Conclusion

A destructor in C++ is an essential part of object-oriented programming that automatically performs cleanup when an object’s lifetime ends. While constructors prepare an object for use, destructors ensure that all acquired resources—such as dynamically allocated memory, files, network connections, and hardware resources—are released safely before the object is destroyed.

In this article, you learned what a destructor is, why it is needed, how it works, the order of constructor and destructor execution, the importance of virtual destructors, and the key differences between constructors and destructors. You also explored best practices, common mistakes, real-world applications, and frequently asked interview questions.

By mastering destructors, you can write C++ programs that are more reliable, memory-efficient, and easier to maintain. Whether you are developing desktop software, embedded systems, IoT applications, or enterprise solutions, understanding destructors is fundamental to effective resource management and professional C++ programming.

Talk to Academic Advisor

Frequently Asked Questions

A destructor is a special member function that automatically executes when an object’s lifetime ends to release resources and perform cleanup.

No. Every class can have only one destructor.

Author

Embedded Systems trainer – IIES

Updated On: 02-07-26


10+ years of hands-on experience delivering practical training in Embedded Systems and it's design