Destructor — RAII principle
WHAT is a destructor?
When does "lifetime end"? Three common cases:
- A local (stack) object goes out of scope (reaches
}or areturn/throw). - A
deleteis called on a heap object (delete p;). - A program/
mainends, destroying static/global objects.
WHY does RAII exist? (Steel-man the manual way first)
The "manual" approach feels fine:
void f() {
int* p = new int[100]; // acquire
// ... use p ...
delete[] p; // release
}It feels safe because the delete[] is right there. But what if // use p throws an exception? Control jumps straight out of f, skipping delete[] p → memory leak. What if someone adds an early return in the middle six months later? Same leak. Manual cleanup is correct only on the happy path.
HOW to build an RAII wrapper (derivation from scratch)
Goal: make raw memory safe. Step by step, asking why at each step.
class IntArray {
int* data; // the owned resource
size_t n;
public:
IntArray(size_t size) // ACQUIRE in constructor
: data(new int[size]), n(size) {} // Why? RAII: acquisition = initialization
~IntArray() { delete[] data; } // RELEASE in destructor
// Why? guaranteed to run on every exit path
int& operator[](size_t i) { return data[i]; } // Why? use it like an array
size_t size() const { return n; }
};
void f() {
IntArray a(100); // acquire
a[0] = 42;
// ... even if this throws, ~IntArray runs and frees data ...
} // destructor fires here — automatic delete[]Why this works on the exception path: during stack unwinding, every fully-constructed local object on the stack has its destructor called. a is one of them ⇒ no leak.

Order of destruction (the LIFO rule)
Why reverse? Later objects may depend on earlier ones. Tearing down in LIFO order guarantees a dependency is still alive while whatever uses it is being destroyed.
Worked examples
Recall Feynman: explain to a 12-year-old
Imagine you borrow a library book (the resource). Instead of trusting yourself to return it, you make a magic backpack: the moment you put the book in, a timer starts, and when you leave the building the backpack automatically returns the book — even if you run out in a panic (an exception!). The backpack is the C++ object, putting the book in is the constructor, and the auto-return is the destructor. You never forget, because the building's exit (end of scope) does the returning for you.
Flashcards
What does RAII stand for and what is its core idea?
When exactly does a destructor run?
delete on a heap object, or program end for statics/globals; also during stack unwinding from an exception.Why is RAII safer than manual new/delete?
What is the Rule of Three?
Why must a polymorphic base class have a virtual destructor?
delete base_ptr; invokes the derived destructor (then the base one); without virtual only the base destructor runs, leaking derived resources.In what order are objects destroyed?
Can a destructor take parameters or be overloaded?
What is the Rule of Zero?
Connections
- Constructor — initialization
- Rule of Three / Five / Zero
- Smart Pointers — unique_ptr & shared_ptr
- Exception Safety & Stack Unwinding
- Virtual Functions & Polymorphism
- Move Semantics
- std::lock_guard & scope guards
Concept Map
Hinglish (regional understanding)
Intuition Hinglish mein samjho
Dekho, RAII ka matlab hai Resource Acquisition Is Initialization — naam ghabrane wala hai par idea simple hai. Jab bhi tum koi resource lete ho (memory new se, file handle, ya mutex lock), us resource ko ek object ke andar "bandh" do. Object jab banta hai (constructor) tab resource le lo, aur object jab marta hai (destructor) tab resource chhod do. Faayda? C++ guarantee karta hai ki destructor har exit path par chalega — chahe normal return ho, ya beech mein exception aa jaaye. Manual delete likhne mein dikkat ye hai ki agar exception aa gaya to woh delete skip ho jaata hai aur memory leak ho jaati hai.
Socho ek library book example: tum khud yaad rakhne ke bharose mat raho. Ek magic backpack bana lo jo building se nikalte hi book khud return kar de. Backpack = object, book daalna = constructor, auto-return = destructor. Tum bhool bhi jaao to bhi kaam ho jaata hai. Isi tarah std::lock_guard constructor mein lock leta hai aur destructor mein unlock — agar doWork() exception phenke tab bhi unlock guaranteed, deadlock nahi hoga.
Ek important warning: Rule of Three. Agar tumne destructor likha hai jo delete[] karta hai, to default copy shallow copy karega — do objects same pointer ko point karenge aur dono destructor delete[] karenge => double free, crash. Isliye destructor likha to copy constructor aur copy assignment bhi sambhaalo, ya phir Rule of Zero follow karo — raw pointer manage hi mat karo, seedha std::vector ya std::unique_ptr use karo jo khud RAII hai.
Aur ek polymorphism wala point: agar base class pointer se delete karna hai, to base ka destructor virtual hona zaroori hai, warna sirf base ka destructor chalega aur derived ka resource leak ho jaayega. Yaad rakho: "Grab in the Greeting, Drop in the Goodbye" — constructor acquire, destructor release.