Smart Pointers & Memory Management in Modern C++ (unique_ptr, shared_ptr, weak_ptr)
๐ด Advanced
๐ Definition
In modern C++ (C++11 and beyond), Smart Pointers are container wrapper classes provided by <memory> that manage the lifetime of heap-allocated dynamic memory through RAII (Resource Acquisition Is Initialization). Smart pointers automatically deallocate heap memory when their scope ends, completely eliminating manual delete statements, raw pointer dangling bugs, and memory leaks!
๐ฎ๐ณ Hindi Explanation
Purane C++ mein jab hum new se heap memory allocate karte the, toh humein delete karke memory free karni padti thi. Agar delete bhool gaye, toh memory leak ho jata tha. Smart Pointers (std::unique_ptr, std::shared_ptr) modern C++ ka sabse zaroori feature hain. Yeh raw pointers ko wrap kar lete hain aur jaise hi pointer scope se bahar jata hai, heap memory ko apne aap delete kar dete hain!
๐ฉ Marathi Explanation
C++11 paasun raw pointers aani manual delete vaparanyapradhane Smart Pointers (std::unique_ptr, std::shared_ptr) vaparale jaataat. Smart pointer mhanje eka dynamic memory vr wrapper. Object cha scope samplyavar smart pointer aapoap heap memory delete karto, jyamule memory leaks hot nahit.
๐ The 3 Smart Pointer Types Compared
| Smart Pointer | Ownership Rule | Copyable? | Movable? | Ideal Use Case |
|---|---|---|---|---|
std::unique_ptr |
Exclusive Ownership (1 owner only!) | โ No | โ
Yes (std::move) |
Default choice! Fast, zero overhead |
std::shared_ptr |
Shared Ownership (Ref-counted) | โ Yes | โ Yes | Shared resources across multiple owners |
std::weak_ptr |
Non-owning Observer | โ Yes | โ Yes | Breaks circular reference deadlocks |
๐ก Practical Example
#include <iostream>
#include <memory>
#include <string>
class Resource {
private:
std::string name;
public:
Resource(std::string resName) : name(resName) {
std::cout << "[ALLOCATED] Heap Resource: " << name << std::endl;
}
~Resource() {
std::cout << "[DESTROYED] Heap Resource: " << name << " (Auto-freed!)" << std::endl;
}
void doWork() const {
std::cout << "Working with Resource: " << name << std::endl;
}
};
int main() {
std::cout << "--- 1. DEMO: std::unique_ptr (Exclusive Ownership) ---" << std::endl;
{
// Recommended helper: std::make_unique (C++14)
std::unique_ptr<Resource> uPtr1 = std::make_unique<Resource>("UniqueDB");
uPtr1->doWork();
// std::unique_ptr CANNOT be copied!
// std::unique_ptr<Resource> uPtr2 = uPtr1; // COMPILATION ERROR!
// Ownership can be MOVED using std::move
std::unique_ptr<Resource> uPtr2 = std::move(uPtr1); // uPtr1 is now empty/null
if (!uPtr1) {
std::cout << "uPtr1 is now NULL after std::move." << std::endl;
}
uPtr2->doWork();
} // uPtr2 goes out of scope HERE -> Destructor called automatically!
std::cout << "\n--- 2. DEMO: std::shared_ptr (Shared Reference Counting) ---" << std::endl;
{
std::shared_ptr<Resource> sPtr1 = std::make_shared<Resource>("SharedCache");
std::cout << "Reference Count: " << sPtr1.use_count() << std::endl;
{
// Copying std::shared_ptr INCREMENTS reference counter!
std::shared_ptr<Resource> sPtr2 = sPtr1;
std::cout << "Reference Count inside inner scope: " << sPtr1.use_count() << std::endl;
sPtr2->doWork();
} // sPtr2 goes out of scope HERE -> Ref count decremented back to 1!
std::cout << "Reference Count after inner scope ends: " << sPtr1.use_count() << std::endl;
} // sPtr1 goes out of scope HERE -> Ref count reaches 0 -> Memory freed automatically!
std::cout << "--- END OF MAIN ---" << std::endl;
return 0;
}
๐ Code Breakdown
std::make_unique<Resource>("UniqueDB"): AllocatesResourceon the heap and wraps it inside aunique_ptr.std::move(uPtr1): Transfers exclusive ownership fromuPtr1touPtr2.sPtr1.use_count(): Inspects the internal reference counter ofstd::shared_ptr. Whenuse_count()drops to0,deleteexecutes automatically.
๐ Output
--- 1. DEMO: std::unique_ptr (Exclusive Ownership) ---
[ALLOCATED] Heap Resource: UniqueDB
Working with Resource: UniqueDB
uPtr1 is now NULL after std::move.
Working with Resource: UniqueDB
[DESTROYED] Heap Resource: UniqueDB (Auto-freed!)
--- 2. DEMO: std::shared_ptr (Shared Reference Counting) ---
[ALLOCATED] Heap Resource: SharedCache
Reference Count: 1
Reference Count inside inner scope: 2
Working with Resource: SharedCache
Reference Count after inner scope ends: 1
[DESTROYED] Heap Resource: SharedCache (Auto-freed!)
--- END OF MAIN ---
โ ๏ธ Common Mistakes
- Using Raw
newanddeletein Modern C++: Manual memory management leads to dangling pointers and memory leaks. Usestd::make_uniqueorstd::make_sharedinstead. - Circular Reference Memory Leak with
shared_ptr: If Object A holds ashared_ptrto Object B, and Object B holds ashared_ptrto Object A, their reference counts never reach 0! Usestd::weak_ptrfor back-references to break circular loops.
๐ก๏ธ Best Practices
- Make
std::unique_ptryour default smart pointer choice unless shared ownership is strictly required. - Always use factory functions
std::make_unique(C++14) andstd::make_shared(C++11) for safety and exception performance.
๐งช Try It Yourself
- Allocate a dynamic
std::vector<int>inside astd::unique_ptr, populate 5 numbers, and iterate over them. - Inspect
use_count()of astd::shared_ptras you pass it to functions by value vs by reference.
๐ฏ Mini Challenge
Implement a TreeNode class where a parent node owns its children using std::vector<std::unique_ptr<TreeNode>>. Demonstrate tree creation and automated cleanup.
๐ Related Topics
๐งญ Navigation
| โ C++ Home | โ Previous: Operator Overloading | Next: STL Containers โ |