C++ Destructor: Memory Cleanup & Resource Management
Module 15: Destructor in C++
A destructor is a special member function that is automatically called when an object is destroyed or goes out of scope. Its primary purpose is to release resources, such as dynamically allocated memory, file handles, database connections, and network sockets.
Unlike constructors, which initialize objects, destructors perform cleanup operations before an object is removed from memory.
Why Do We Need Destructors?
Destructors help prevent:
- Memory leaks
- Resource leaks
- File handle leaks
- Database connection leaks
- Network socket leaks
Without proper cleanup, programs may consume unnecessary memory and system resources.
Example
1int* ptr = new int(100); 2 3// Without delete, memory remains allocated.
A destructor ensures such resources are released automatically.
Syntax
A destructor:
- Has the same name as the class.
- Starts with the
~(tilde) symbol. - Has no return type.
- Takes no parameters.
- Only one destructor is allowed per class.
Syntax
1class ClassName 2{ 3public: 4 ~ClassName() 5 { 6 // Cleanup code 7 } 8};
Basic Destructor Example
1#include <iostream> 2 3using namespace std; 4 5class Student 6{ 7public: 8 Student() 9 { 10 cout << "Constructor Called" << endl; 11 } 12 13 ~Student() 14 { 15 cout << "Destructor Called"; 16 } 17}; 18 19int main() 20{ 21 Student s; 22 23 return 0; 24}
Output
1Constructor Called 2Destructor Called
The destructor is automatically called when s goes out of scope.
Memory Cleanup
Destructors are commonly used to release dynamically allocated memory.
Example
1#include <iostream> 2 3using namespace std; 4 5class Number 6{ 7private: 8 int* data; 9 10public: 11 Number() 12 { 13 data = new int(100); 14 } 15 16 ~Number() 17 { 18 delete data; 19 cout << "Memory Released"; 20 } 21}; 22 23int main() 24{ 25 Number obj; 26 27 return 0; 28}
Output
1Memory Released
Without the destructor, the allocated memory would remain in use, causing a memory leak.
Resource Management
Destructors can also release other system resources.
Example: Closing a File
1#include <fstream> 2 3using namespace std; 4 5class FileManager 6{ 7private: 8 ofstream file; 9 10public: 11 FileManager() 12 { 13 file.open("data.txt"); 14 } 15 16 ~FileManager() 17 { 18 if (file.is_open()) 19 { 20 file.close(); 21 } 22 } 23};
The file is automatically closed when the object is destroyed.
Destructor Execution Order
When an object is destroyed:
- The destructor body executes.
- Class members are destroyed.
- Base class destructors are called (for inherited classes).
Example
1#include <iostream> 2 3using namespace std; 4 5class Base 6{ 7public: 8 ~Base() 9 { 10 cout << "Base Destructor" << endl; 11 } 12}; 13 14class Derived : public Base 15{ 16public: 17 ~Derived() 18 { 19 cout << "Derived Destructor" << endl; 20 } 21}; 22 23int main() 24{ 25 Derived obj; 26 27 return 0; 28}
Output
1Derived Destructor 2Base Destructor
Constructor vs Destructor
| Constructor | Destructor |
|---|---|
| Initializes an object | Cleans up an object |
| Called when object is created | Called when object is destroyed |
| Same name as class | Same name prefixed with ~ |
| Can have parameters | Cannot have parameters |
| Can be overloaded | Cannot be overloaded |
Best Practices
- Release all dynamically allocated memory in the destructor.
- Close files, sockets, and database connections in the destructor.
- Avoid throwing exceptions from destructors.
- Use smart pointers (
std::unique_ptr,std::shared_ptr) whenever possible to simplify resource management. - Follow the RAII (Resource Acquisition Is Initialization) principle.
Common Mistakes
Forgetting to Release Memory
❌ Incorrect
1class Demo 2{ 3 int* ptr; 4 5public: 6 Demo() 7 { 8 ptr = new int(50); 9 } 10};
This causes a memory leak.
Correct
1class Demo 2{ 3 int* ptr; 4 5public: 6 Demo() 7 { 8 ptr = new int(50); 9 } 10 11 ~Demo() 12 { 13 delete ptr; 14 } 15};
Practice Problems
- Create a class with a destructor that prints a message.
- Allocate memory using
newand release it in the destructor. - Create a class that automatically closes a file.
- Demonstrate the order of constructor and destructor calls.
- Compare destructor behavior for stack and heap objects.
Interview Questions
- What is a destructor in C++?
- Why do we need destructors?
- What is the syntax of a destructor?
- Can a destructor have parameters?
- Can a class have multiple destructors?
- When is a destructor automatically called?
- How do destructors help prevent memory leaks?
- What is the relationship between destructors and RAII?
- What is the order of destructor execution in inheritance?
Summary
In this module, you learned:
- What a destructor is and why it is important.
- The syntax and characteristics of destructors.
- How destructors automatically clean up dynamically allocated memory.
- How destructors manage system resources such as files and connections.
- The difference between constructors and destructors.
- Best practices for writing safe and efficient destructors.
Next Module: Module 16: Inheritance — Single, Multiple, Multilevel, Hierarchical, Hybrid Inheritance, Constructor Order, Method Overriding, Virtual Inheritance, and Access Control in Inheritance.