Destructor Deep Dive
Part of the Object Oriented Programming section of Coddy's C++ journey — lesson 24 of 104.
A destructor is a special member function that runs automatically when an object is destroyed. Its primary job is to release resources the object acquired during its lifetime, such as dynamically allocated memory, file handles, or network connections.
The destructor has the same name as the class, prefixed with a tilde ~. It takes no parameters and has no return type:
class FileHandler {
std::string filename;
int* buffer;
public:
FileHandler(std::string name, size_t size)
: filename(name), buffer(new int[size]) {
std::cout << "Opening " << filename << "\n";
}
~FileHandler() {
delete[] buffer;
std::cout << "Closing " << filename << "\n";
}
};Destructors are called automatically in these situations:
- Stack objects go out of scope
deleteis called on a heap-allocated object- A temporary object's lifetime ends
void example() {
FileHandler f1("data.txt", 100); // Constructor called
FileHandler* f2 = new FileHandler("log.txt", 50);
delete f2; // Destructor called for f2
} // Destructor called for f1 (goes out of scope)Unlike constructors, a class can have only one destructor. You cannot overload it.
If you don't define one, the compiler generates a default destructor that does nothing special - it simply destroys each member. For classes managing resources, you must write your own to prevent memory leaks.
Challenge
EasyLet's build a session manager that tracks active user sessions and demonstrates how destructors automatically clean up resources when objects are destroyed — whether they go out of scope or are explicitly deleted.
You'll create two files to organize your code:
Session.h: Define aSessionclass that represents an active user session with dynamically allocated data. Your class should have:- Private members: a
username(string), asessionId(int), and a pointer to an integer array calledactivityLogthat tracks user actions, along with alogSizefor the array size - A constructor that takes a username, session ID, and log size. It should allocate the activity log array on the heap, initialize all elements to 0, and print
"Session <sessionId> started for <username>" - A destructor that frees the allocated memory and prints
"Session <sessionId> ended for <username>" - A
logActivity(int activityCode)method that stores the activity code in the next available slot (track the current position internally) - A
getActivityCount()method that returns how many activities have been logged - A
getUsername()method that returns the username
- Private members: a
main.cpp: Demonstrate destructor behavior in different scenarios. Read a username and log size from input (each on a separate line), then:- Create a scope block using curly braces
{ }and inside it create a stack-allocatedSessionwith the input username, session ID101, and the input log size. Log two activities with codes1and2, then print"Stack session activities: <count>". When the block ends, the destructor should run automatically. - After the block, print
"Stack session destroyed" - Create a heap-allocated
Sessionusingnewwith username"Guest", session ID202, and log size3. Log one activity with code5, print"Heap session activities: <count>", then explicitlydeleteit. - After deletion, print
"Heap session destroyed"
- Create a scope block using curly braces
This challenge shows the two main ways destructors get called: automatically when stack objects leave scope, and manually when you delete heap objects. Both paths should properly free the dynamically allocated activity log to prevent memory leaks.
Include your header file in main.cpp using #include "Session.h".
Cheat sheet
A destructor is a special member function that runs automatically when an object is destroyed. It releases resources like dynamically allocated memory, file handles, or network connections.
The destructor has the same name as the class, prefixed with a tilde ~. It takes no parameters and has no return type:
class FileHandler {
std::string filename;
int* buffer;
public:
FileHandler(std::string name, size_t size)
: filename(name), buffer(new int[size]) {
std::cout << "Opening " << filename << "\n";
}
~FileHandler() {
delete[] buffer;
std::cout << "Closing " << filename << "\n";
}
};Destructors are called automatically when:
- Stack objects go out of scope
deleteis called on a heap-allocated object- A temporary object's lifetime ends
void example() {
FileHandler f1("data.txt", 100); // Constructor called
FileHandler* f2 = new FileHandler("log.txt", 50);
delete f2; // Destructor called for f2
} // Destructor called for f1 (goes out of scope)A class can have only one destructor (no overloading). If you don't define one, the compiler generates a default destructor. For classes managing resources, you must write your own to prevent memory leaks.
Try it yourself
#include <iostream>
#include <string>
#include "Session.h"
using namespace std;
int main() {
// Read input
string username;
int logSize;
getline(cin, username);
cin >> logSize;
// TODO: Create a scope block with curly braces { }
// Inside the block:
// - Create a stack-allocated Session with the input username, session ID 101, and input log size
// - Log two activities with codes 1 and 2
// - Print "Stack session activities: <count>"
// When the block ends, the destructor runs automatically
// TODO: After the block, print "Stack session destroyed"
// TODO: Create a heap-allocated Session using new
// - Username: "Guest", session ID: 202, log size: 3
// - Log one activity with code 5
// - Print "Heap session activities: <count>"
// - Delete the session
// TODO: After deletion, print "Heap session destroyed"
return 0;
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesC++ Build & CompilationHeader Files & Source FilesNamespaces & ScopeIntroduction to OOP in C++Classes vs ObjectsThe 'this' PointerMethods (Member Functions)Attributes (Data Members)Ctors & Dtors BasicsRecap - Simple Calculator4Class Properties
Instance vs Static MembersGetters and SettersConst Member FunctionsMutable KeywordStatic Methods and VariablesFriend Functions & ClassesRecap - Bank Account Manager7Inheritance
Basic InheritanceInheritance Access LevelsCtor & Dtor Call OrderMethod OverridingVirtual Functions & VTableMultiple InheritanceVirtual InheritanceRecap - Employee Hierarchy2Memory Management
Stack vs Heap MemoryPointers and ReferencesDynamic Memory (new/delete)Smart Pointers in C++RAII in C++Recap - Dynamic Array Manager5Encapsulation
Access Specifiers in C++Access Specifiers In DepthInformation HidingStruct vs ClassNested & Inner ClassesRecap - Student Records System8Polymorphism
Compile vs Runtime PolymorphFunction OverloadingVirtual Functions RevisitedPure Virtual FunctionsAbstract ClassesInterface Design in C++Dynamic Casting & RTTIRecap - Shape Calculator3Constructors & Destructors
Default ConstructorParameterized ConstructorCopy ConstructorMove ConstructorConstructor Init ListsDelegating ConstructorsDestructor Deep DiveRule of Three / Five / ZeroRecap - String Class6Operator Overloading
Intro to Operator OverloadArithmetic Operator OverloadComparison Operator OverloadStream OperatorsAssignment Operator Overload[] and () Operator OverloadType Conversion OperatorsRecap - Matrix Class9Templates
Function TemplatesClass TemplatesTemplate SpecializationVariadic TemplatesSFINAE & Type Traits BasicsRecap - Generic Container