A destructor is a special member function of a class that is automatically called when an object is destroyed. Destructors are mainly used to perform cleanup work, such as releasing resources owned by an object.
~ symbol, and it does not have a return
type or parameters.
A destructor is a special member function that is automatically called when an object is destroyed.
class Student {
public:
~Student() {
std::cout << "Destructor called";
}
};
The destructor is used when the lifetime of a Student
object ends.
The basic syntax of a destructor is:
class ClassName {
public:
~ClassName() {
// cleanup code
}
};
The destructor name must match the class name and begin with
~.
A destructor does not have a return type.
class Demo {
public:
~Demo() {
std::cout << "Destructor";
}
};
You must not write void or any other return type before a
destructor.
A destructor cannot take parameters.
class Demo {
public:
~Demo() {
std::cout << "Object destroyed";
}
};
There can be only one destructor for a class.
A destructor is called automatically when an object's lifetime ends. For a local object, this normally happens when the object goes out of scope.
class Demo {
public:
~Demo() {
std::cout << "Destructor called";
}
};
int main() {
Demo object;
return 0;
}
When main() ends, the local object is destroyed and its
destructor is called.
A local object's destructor is called when the object leaves its scope.
class Demo {
public:
~Demo() {
std::cout << "Destroyed"
<< std::endl;
}
};
int main() {
{
Demo object;
}
std::cout << "After block";
return 0;
}
The destructor runs when the closing brace of the inner block is reached.
#include <iostream>
class Demo {
public:
Demo() {
std::cout << "Constructor called"
<< std::endl;
}
~Demo() {
std::cout << "Destructor called"
<< std::endl;
}
};
int main() {
Demo object;
std::cout << "Inside main"
<< std::endl;
return 0;
}
The constructor runs when the object is created and the destructor runs when its lifetime ends.
| Constructor | Destructor |
|---|---|
| Initializes an object. | Performs cleanup when an object is destroyed. |
| Has the same name as the class. | Has the class name preceded by ~. |
| Can have parameters. | Cannot have parameters. |
| Can be overloaded. | Cannot be overloaded. |
| Called during object initialization. | Called when object lifetime ends. |
Destructors can be used to release resources owned by an object.
class Resource {
public:
Resource() {
std::cout << "Resource acquired";
}
~Resource() {
std::cout << "Resource released";
}
};
The destructor provides a place for cleanup associated with the object's lifetime.
If a class directly owns memory allocated with new, its
destructor can release that memory.
class Array {
private:
int* data;
public:
Array() {
data = new int[5];
}
~Array() {
delete[] data;
}
};
Here, delete[] releases the dynamically allocated array.
When an object created using new is destroyed using
delete, its destructor is called before the object's
storage is released.
class Student {
public:
~Student() {
std::cout << "Destructor called";
}
};
int main() {
Student* student =
new Student();
delete student;
return 0;
}
When dynamically allocated arrays are released with
delete[], destructors for the array elements are invoked.
class Student {
public:
~Student() {
std::cout << "Destroyed"
<< std::endl;
}
};
int main() {
Student* students =
new Student[3];
delete[] students;
return 0;
}
For local objects in the same scope, destruction generally happens in the reverse order of construction.
class Demo {
private:
int id;
public:
Demo(int value)
: id(value) {
}
~Demo() {
std::cout << id
<< std::endl;
}
};
int main() {
Demo first(1);
Demo second(2);
Demo third(3);
return 0;
}
The destructors run in the order:
3
2
1
class Demo {
private:
int id;
public:
Demo(int value)
: id(value) {
}
~Demo() {
std::cout <<
"Destroyed: "
<< id
<< std::endl;
}
};
int main() {
Demo first(1);
{
Demo second(2);
std::cout <<
"Inside block"
<< std::endl;
}
std::cout <<
"Outside block";
return 0;
}
The destructor for second runs when the inner block ends.
A class can have multiple constructors, but it can have only one destructor.
class Demo {
public:
~Demo() {
std::cout << "Destroyed";
}
};
You cannot define another destructor with different parameters because destructors cannot have parameters.
A base class destructor is often declared virtual when
objects of derived classes may be deleted through a base-class
pointer.
class Base {
public:
virtual ~Base() {
std::cout <<
"Base destructor";
}
};
A virtual destructor helps ensure that the appropriate derived destructor is called when deleting through a base pointer.
class Base {
public:
virtual ~Base() {
std::cout <<
"Base destroyed"
<< std::endl;
}
};
class Derived : public Base {
public:
~Derived() {
std::cout <<
"Derived destroyed"
<< std::endl;
}
};
int main() {
Base* object =
new Derived();
delete object;
return 0;
}
With a virtual base destructor, deleting through the base pointer allows the derived destructor to run correctly before the base destructor.
When a derived object is destroyed, the derived destructor runs before the base destructor.
class Base {
public:
virtual ~Base() {
std::cout <<
"Base"
<< std::endl;
}
};
class Derived : public Base {
public:
~Derived() {
std::cout <<
"Derived"
<< std::endl;
}
};
For a derived object, destruction proceeds from the most-derived part toward the base part.
When an object is destroyed, its member objects are also destroyed according to C++ object lifetime rules.
class Engine {
public:
~Engine() {
std::cout <<
"Engine destroyed"
<< std::endl;
}
};
class Car {
private:
Engine engine;
public:
~Car() {
std::cout <<
"Car destructor"
<< std::endl;
}
};
Member objects are destroyed after the containing object's destructor body finishes.
A class that owns a resource such as a file handle can use its destructor as part of cleanup.
class FileManager {
public:
FileManager() {
std::cout <<
"File opened"
<< std::endl;
}
~FileManager() {
std::cout <<
"File closed"
<< std::endl;
}
};
In real programs, standard library resource-management types are often preferred because they automatically manage resources safely.
Destructors are an important part of C++ resource management because local objects are destroyed automatically when their scope ends, even when control leaves the scope because of an exception.
class Resource {
public:
~Resource() {
std::cout <<
"Cleanup";
}
};
void process() {
Resource resource;
// Work happens here.
}
This behavior is one of the foundations of RAII in C++.
RAII means Resource Acquisition Is Initialization. In C++, a resource can be associated with an object's lifetime so that its destructor performs cleanup automatically.
class ResourceManager {
public:
ResourceManager() {
// Acquire resource
}
~ResourceManager() {
// Release resource
}
};
RAII is a major C++ technique for safe resource management.
#include <iostream>
class Student {
private:
int id;
public:
Student(int studentId)
: id(studentId) {
std::cout <<
"Student created: "
<< id
<< std::endl;
}
~Student() {
std::cout <<
"Student destroyed: "
<< id
<< std::endl;
}
};
int main() {
Student student(101);
std::cout <<
"Student is active"
<< std::endl;
return 0;
}
#include <iostream>
class Numbers {
private:
int* data;
public:
Numbers(int size) {
data = new int[size];
std::cout <<
"Array allocated"
<< std::endl;
}
~Numbers() {
delete[] data;
std::cout <<
"Array released"
<< std::endl;
}
};
int main() {
Numbers numbers(10);
return 0;
}
std::vector or other RAII-based types instead of manually
managing dynamic arrays whenever possible.
#include <iostream>
class DatabaseConnection {
public:
DatabaseConnection() {
std::cout <<
"Database connected"
<< std::endl;
}
~DatabaseConnection() {
std::cout <<
"Database connection closed"
<< std::endl;
}
};
void processData() {
DatabaseConnection connection;
std::cout <<
"Processing data"
<< std::endl;
}
int main() {
processData();
std::cout <<
"Program continues";
return 0;
}
When processData() finishes, the local
connection object is destroyed and its destructor runs.
delete instead of delete[] for an array allocated with new[].| Destructor | delete |
|---|---|
| A special member function of a class. | An operator used to destroy an object created with new. |
| Runs as part of object destruction. | Causes destruction of a dynamically allocated object and releases its storage. |
Written using ~ClassName(). |
Written as delete pointer. |
| Cannot be called with parameters. | Used with a pointer to dynamically allocated storage. |
delete with new and delete[] with new[] when manual memory management is used.Destructors are especially important for classes that manage resources.
| Concept | Meaning |
|---|---|
| Destructor | A special member function called when an object is destroyed. |
| Syntax | ~ClassName() |
| Return Type | A destructor has no return type. |
| Parameters | A destructor cannot have parameters. |
| Overloading | A class cannot have multiple destructors. |
| Cleanup | Destructors can release resources owned by an object. |
| Virtual Destructor | Useful in polymorphic base classes for correct destruction through base pointers. |
| RAII | Associates resource management with object lifetime. |
class Student {
public:
Student() {
std::cout <<
"Object created"
<< std::endl;
}
~Student() {
std::cout <<
"Object destroyed"
<< std::endl;
}
};
int main() {
Student student;
return 0;
}
~ prefix.new are destroyed using delete, which invokes their destructor.new[] should be released with delete[].Question: Which statement about a C++ destructor is correct?