In C++, a destructor is a special member function of a class that is responsible for cleaning up resources and performing necessary actions before an object is destroyed or goes out of scope. The destructor is automatically called when an object is no longer needed, either because it is explicitly deleted or because it goes out of scope.
The primary purpose of a destructor is to release any resources acquired by the object during its lifetime. This may include freeing dynamically allocated memory, closing files, releasing network connections, or performing any other cleanup operations.
The syntax for a destructor is similar to that of a constructor, but it is preceded by a tilde (~). Here's the general form:
class ClassName { public: // Constructor ClassName() { // Constructor code } // Destructor ~ClassName() { // Destructor code } };
{ ClassName obj; // Object created } // Object goes out of scope, destructor called
It's important to note that if a class doesn't define its own destructor, C++ provides a default destructor. However, the default destructor may not be sufficient for classes that manage dynamic resources, and in such cases, a custom destructor should be implemented to ensure proper cleanup.
#include <iostream> class ResourceHolder { public: // Constructor ResourceHolder() { std::cout << "Constructor: Resource acquired\n"; } // Destructor ~ResourceHolder() { std::cout << "Destructor: Cleaning up resources\n"; // Code to release resources (e.g., free memory, close files, etc.) } }; int main() { ResourceHolder obj; // Constructor called // Do some work with obj // obj goes out of scope, destructor called automatically return 0; }
If a class does not have a user-defined destructor, the compiler provides a default destructor. It has an empty body and is automatically called when an object goes out of scope or is explicitly deleted.
class MyClass { // No user-defined destructor };
A user-defined destructor is explicitly declared and defined by the programmer. It performs specific cleanup operations when an object is destroyed. It replaces the default destructor if provided.
class MyClass {
public:
// Constructor (if needed)
MyClass() {
// Initialization code
}
// Other class members...
// User-defined destructor
~MyClass() {
// Cleanup code (e.g., releasing resources)
}
};
#include <iostream> using namespace std; class Test { private: static int count; // Static member variable to count objects public: // Constructor Test() { count++; cout << "No. of Objects created: " << count << endl; } // Destructor ~Test() { cout << "No. of Objects destroyed: " << count << endl; count--; } }; int Test::count = 0; // Initializing static member variable // Driver code int main() { Test t1, t2, t3; return 0; }
No. of Objects created: 1 No. of Objects created: 2 No. of Objects created: 3 No. of Objects destroyed: 3 No. of Objects destroyed: 2 No. of Objects destroyed: 1
#include <iostream> using namespace std; class MyClass { public: MyClass() { cout << "Constructor called Object address: " << this << endl; } ~MyClass() { cout << "Destructor called Object address: " <<this << endl; } }; int main() { cout << endl<< endl << "Creating object obj1" << endl<< endl; MyClass obj1; // Constructor called { cout << endl<< endl<< "Creating object obj2" << endl<< endl; MyClass obj2; // Constructor called }// Destructor called for obj2 when it goes out of scope cout << endl<< endl<< "Creating object obj3" << endl<< endl; MyClass obj3; // Constructor called return 0; } // Destructor called for obj1 when main() exits
Creating object obj1 Constructor called Object address: 0x6ffe0f Creating object obj2 Constructor called Object address: 0x6ffe0d Destructor called Object address: 0x6ffe0d Creating object obj3 Constructor called Object address: 0x6ffe0e Destructor called Object address: 0x6ffe0e Destructor called Object address: 0x6ffe0f
In C++, destructors are automatically called when an object goes out of scope or is explicitly deleted. However, you cannot directly call a destructor like a regular member function. Instead, you can destroy an object explicitly using the delete keyword, which triggers the destructor call. Here's a very simple example:
#includeusing namespace std; class MyClass { public: ~MyClass() { cout << "Destructor called" << endl; } }; int main() { MyClass* obj = new MyClass(); // Creating object dynamically // Deleting object explicitly, which calls the destructor delete obj; return 0; }
Aspect | Destructor | Delete Operator |
---|---|---|
Definition | A special member function in a class that is automatically called when an object goes out of scope or is explicitly deleted. | An operator in C++ used to deallocate memory that was previously allocated using the new operator. |
Usage | Part of the class definition and is automatically invoked when an object's lifetime ends. | Used explicitly to free the memory allocated dynamically using new. |
Memory Deallocation | Primarily used for releasing resources, closing files, or any cleanup operations within the class. | Specifically used for deallocating memory previously allocated on the heap with new. |
Order of Execution | Called automatically in the reverse order of object construction during stack unwinding. | Not related to the order of object construction; manually invoked when needed. |
Scope | Applies to objects with automatic or dynamic storage duration. | Primarily used for objects with dynamic storage duration (allocated on the heap). |
Aspect | Dynamic Memory | Destructors |
---|---|---|
Allocation | Allocated using operators like `new` or `malloc` on the heap. | Automatic memory allocation occurs when objects are created, with destructors responsible for cleanup. |
Deallocation | Manual deallocation using operators like `delete` or `free` is required to avoid memory leaks. | Automatic deallocation occurs when objects go out of scope or are explicitly deleted, handled by the destructor. |
Lifetime | Objects have a dynamic lifetime, persisting until explicitly deallocated. | Objects have a scoped or dynamic lifetime, with destructors managing cleanup during their destruction. |
Responsibility | The programmer is responsible for both allocation and deallocation of memory. | Destructors are responsible for releasing resources, including dynamic memory, when objects are destroyed. |
Resource Management | Requires careful management to avoid memory leaks or dangling pointers. | Provides a structured approach to resource management, enhancing code reliability and robustness. |
Exceptions | Memory leaks may occur if deallocation is not performed correctly. | Destructors contribute to exception safety, ensuring cleanup even in the presence of exceptions. |
Aspect | Base Class | Derived Class |
---|---|---|
Definition | May have a user-defined or default destructor. | May have a user-defined or default destructor. |
Order of Execution | Base class destructor is called first during destruction. | Derived class destructor is called after the base class destructor. |
User-Defined Destructor | Can contain custom cleanup logic for the base class. | Can contain custom cleanup logic for the derived class in addition to the base class. |
Default Destructor | Used if no user-defined destructor is provided. | Used if no user-defined destructor is provided; calls the base class default destructor. |
Implicit Call | Automatically called when an object of the base class is destroyed. | Automatically calls the base class destructor before executing its own destructor. |
Explicit Call | Can be explicitly called by the derived class, but this is less common. | Can be explicitly called by the derived class, but this is less common. Generally, the base class destructor is implicitly called. |