Dynamic Memory: new/delete vs Smart Pointers
ডায়নামিক মেমরি — heap ও RAII
1. Stack vs Heap
| Aspect | Stack | Heap |
|---|---|---|
| Lifetime | Until end of scope | Until you free it |
| Speed | Very fast (just bump SP) | Slower (allocator work) |
| Size | Small (~MB) | Huge (limited by OS) |
| Allocate | Automatic | new / malloc |
| Free | Automatic | delete / free |
2. new and delete — The Old Way
#include <iostream>
int main() {
int* p = new int(42); // allocate one int on heap
std::cout << *p << "\n";
delete p; // MUST free
int* arr = new int[5]{1,2,3,4,5};
delete[] arr; // note: delete[]
}
- Forget to
delete→ memory leak deletetwice → undefined behavior (double-free)- Use after
delete→ undefined behavior (use-after-free) deleteinstead ofdelete[]→ undefined behavior
3. std::unique_ptr — The Modern Way
Owns one heap object. Deletes it when the smart pointer goes out of scope.
#include <iostream>
#include <memory>
struct Widget {
Widget() { std::cout << "created\n"; }
~Widget() { std::cout << "destroyed\n"; }
};
int main() {
auto w = std::make_unique<Widget>();
std::cout << "using widget...\n";
// no delete — auto cleanup at scope end
}
4. RAII — The Big Idea
Resource Acquisition Is Initialization: tie a resource (memory, file handle, lock) to an object's lifetime. The destructor releases it. Exception thrown? Stack unwinds, destructors run, no leak.
5. Memory Tools
- AddressSanitizer (ASan):
g++ -fsanitize=address. Catches leaks, use-after-free, double-free. - Valgrind:
valgrind ./myapp. Linux-only, slow but thorough. - UndefinedBehaviorSanitizer:
-fsanitize=undefined. Catches signed overflow, null deref, etc.
6. Practice Problems
- Allocate an int=99 with new. Print and delete.
✨ Show Answer
int* p = new int(99); std::cout << *p; delete p; - Same with unique_ptr.
✨ Show Answer
auto p = std::make_unique<int>(99); std::cout << *p; // auto-deletes - What's a "memory leak"?
✨ Show Answer
Heap memory you allocated but never freed. The OS reclaims it when the process exits, but a long-running server slowly bloats and crashes.
- Why use
make_uniqueinstead ofnew?✨ Show Answer
Exception safety: in
f(unique_ptr<T>(new T), g()), ifg()throws betweennewand the constructor of unique_ptr, you leak.make_uniqueavoids this. - Allocate an array of 100 doubles.
✨ Show Answer
auto arr = std::make_unique<double[]>(100); - Pass unique_ptr to a function — what happens?
✨ Show Answer
Cannot copy. Either pass by value with
std::move(transfers ownership), or by reference for non-owning use. - Difference between
delete panddelete[] p?✨ Show Answer
deletecalls one destructor and frees a single object.delete[]calls each element's destructor and frees an array. Mixing them is UB. - Show why double-delete is bad.
✨ Show Answer
int* p = new int; delete p; delete p; // UB: heap corruption likely - Use ASan to find leaks: command line?
✨ Show Answer
g++ -fsanitize=address -g app.cpp -o app ./appASan prints leaks at exit.
- Why is RAII the central idea of C++?
✨ Show Answer
Resource cleanup happens automatically when objects go out of scope, even on exceptions. No manual cleanup, no leaks. It's how modern C++ achieves safety without GC.
- Stack or heap:
int x = 5;✨ Show Answer
Stack (automatic).
- Stack or heap:
int* p = new int(5);✨ Show Answer
The pointer
pis on the stack; the int it points to is on the heap. - Why is heap allocation slower than stack?
✨ Show Answer
Stack alloc = adjust SP register (~1 cycle). Heap alloc = traverse free list, possibly request memory from OS, possibly take a lock — orders of magnitude slower.
- When MUST you use
new/deletedirectly?✨ Show Answer
Almost never. The only legitimate cases: implementing your own container, custom allocator, or interop with a C API that frees with the matching primitive.
- What if a constructor throws after partial allocation?
✨ Show Answer
Already-constructed members are destroyed (RAII). The object is never "partially" alive.
new T(...)deallocates if T's constructor throws. Smart pointers leverage this. - What does
nullptr_thave to do with smart pointers?✨ Show Answer
You can compare smart pointers to
nullptr:if (!p) ...means "if not yet owning anything". - Demonstrate exception safety with unique_ptr.
✨ Show Answer
auto p = std::make_unique<Widget>(); throw std::runtime_error{"oops"}; // Widget still gets destroyed during stack unwind! - Can a unique_ptr be copied?
✨ Show Answer
No. Copying would mean two owners — violates the "sole owner" invariant. It can be moved (transferring ownership).
Summary
Modern C++ avoids raw new/delete. Use std::make_unique for sole ownership and
std::make_shared for shared ownership (Module 32). RAII makes leaks impossible — destructors
run automatically, even on exceptions. Compile with -fsanitize=address to catch any remaining bugs.