Smart_pointers
Smart Pointers
Section titled “Smart Pointers”Smart pointers are wrapper classes that automatically manage memory. They are a key feature of modern C++ (C++11 and later) that help prevent memory leaks.
Why Smart Pointers?
Section titled “Why Smart Pointers?”┌─────────────────────────────────────────────────────────────┐│ Smart Pointers Overview │├─────────────────────────────────────────────────────────────┤│ ││ Raw Pointer Problems: Smart Pointer Solutions: ││ ┌──────────────────┐ ┌──────────────────┐ ││ │ • Memory leaks │ │ • Auto cleanup │ ││ │ • Dangling ptrs │ │ • Exception safe │ ││ │ • Double delete │ │ • Ownership │ ││ │ • Exception unsafe│ │ semantics │ ││ └──────────────────┘ └──────────────────┘ ││ ││ Types: ││ • unique_ptr - exclusive ownership ││ • shared_ptr - shared ownership ││ • weak_ptr - non-owning reference ││ │└─────────────────────────────────────────────────────────────┘std::unique_ptr
Section titled “std::unique_ptr”Exclusive ownership - only one pointer can own the resource:
#include <memory>
int main() { // Create unique pointer std::unique_ptr<int> ptr1 = std::make_unique<int>(42);
// Access value std::cout << *ptr1 << "\n"; // 42 std::cout << ptr1.get() << "\n"; // Memory address
// Transfer ownership std::unique_ptr<int> ptr2 = std::move(ptr1); // ptr1 is now nullptr
// Release ownership int* raw = ptr2.release(); delete raw;}unique_ptr with Arrays
Section titled “unique_ptr with Arrays”// For arrays, specify typestd::unique_ptr<int[]> arr = std::make_unique<int[]>(10);arr[0] = 42;std::cout << arr[0] << "\n";// Automatically deletes[] when goes out of scopeCustom Deleter
Section titled “Custom Deleter”#include <memory>#include <fstream>
// Custom deleter for FILEauto fileDeleter = [](FILE* f) { if (f) fclose(f);};
std::unique_ptr<FILE, decltype(fileDeleter)> file(fopen("test.txt", "r"), fileDeleter);std::shared_ptr
Section titled “std::shared_ptr”Shared ownership - reference counted:
#include <memory>
int main() { std::shared_ptr<int> ptr1 = std::make_shared<int>(42);
// Copy creates another shared pointer std::shared_ptr<int> ptr2 = ptr1;
std::cout << *ptr1 << "\n"; // 42 std::cout << *ptr2 << "\n"; // 42
std::cout << ptr1.use_count() << "\n"; // 2
// Reset releases ownership ptr1.reset(); std::cout << ptr2.use_count() << "\n"; // 1}shared_ptr with Custom Deleter
Section titled “shared_ptr with Custom Deleter”std::shared_ptr<int> ptr( new int(42), [](int* p) { std::cout << "Custom deleter called\n"; delete p; });Make Shared is Efficient
Section titled “Make Shared is Efficient”// Preferred wayauto ptr = std::make_shared<MyClass>(args);
// Why it's efficient: control block and object allocated together// Control block contains: reference count, deleter, allocatorstd::weak_ptr
Section titled “std::weak_ptr”Non-owning reference to shared_ptr:
#include <memory>
int main() { std::shared_ptr<int> shared = std::make_shared<int>(42);
std::weak_ptr<int> weak = shared;
// Check if expired if (!weak.expired()) { // Get shared_ptr from weak std::shared_ptr<int> ptr = weak.lock(); std::cout << *ptr << "\n"; }
// Reset shared shared.reset();
// Now expired if (weak.expired()) { std::cout << "weak_ptr expired\n"; }}Weak Pointer Use Case: Caches
Section titled “Weak Pointer Use Case: Caches”class Node {public: std::shared_ptr<Node> next; std::weak_ptr<Node> prev; // Back-reference without ownership
~Node() { std::cout << "Node destroyed\n"; }};Converting Between Smart Pointers
Section titled “Converting Between Smart Pointers”// unique_ptr to shared_ptrstd::unique_ptr<int> unique = std::make_unique<int>(42);std::shared_ptr<int> shared = std::move(unique);
// shared_ptr to weak_ptrstd::weak_ptr<int> weak = shared;
// weak_ptr to shared_ptr (if still valid)if (auto ptr = weak.lock()) { // Use ptr}Smart Pointers with Containers
Section titled “Smart Pointers with Containers”#include <vector>#include <memory>
int main() { // Vector of unique pointers std::vector<std::unique_ptr<int>> vec; vec.push_back(std::make_unique<int>(1)); vec.push_back(std::make_unique<int>(2));
// Can't copy unique_ptr, must move // vec.push_back(unique); // Error! vec.push_back(std::move(unique));
// Vector of shared pointers (can copy) std::vector<std::shared_ptr<int>> svec; svec.push_back(std::make_shared<int>(1)); svec.push_back(std::make_shared<int>(2));}Complete Example
Section titled “Complete Example”#include <iostream>#include <memory>#include <vector>
class Resource {private: std::string name;
public: Resource(const std::string& n) : name(n) { std::cout << "Acquired: " << name << "\n"; }
~Resource() { std::cout << "Released: " << name << "\n"; }
void use() { std::cout << "Using: " << name << "\n"; }};
int main() { std::cout << "=== unique_ptr ===\n"; { auto ptr = std::make_unique<Resource>("File"); ptr->use(); } // Automatically deleted
std::cout << "\n=== shared_ptr ===\n"; { auto ptr1 = std::make_shared<Resource>("Memory"); auto ptr2 = ptr1;
std::cout << "use_count: " << ptr1.use_count() << "\n"; ptr1->use(); ptr2->use(); } // Deleted when last shared_ptr goes away
std::cout << "\n=== weak_ptr ===\n"; { auto shared = std::make_shared<Resource>("Cache"); std::weak_ptr<Resource> weak = shared;
if (auto ptr = weak.lock()) { ptr->use(); }
shared.reset();
if (weak.expired()) { std::cout << "Resource expired\n"; } }
return 0;}When to Use Which
Section titled “When to Use Which”| Use Case | Smart Pointer |
|---|---|
| Single owner | std::unique_ptr |
| Multiple owners | std::shared_ptr |
| Observer/reference without ownership | std::weak_ptr |
| Old C APIs | std::unique_ptr with custom deleter |
Best Practices
Section titled “Best Practices”- Prefer
std::make_uniqueandstd::make_shared - Use
unique_ptrby default - Only use
shared_ptrwhen ownership is truly shared - Use
weak_ptrfor caches and observers - Don’t mix raw and smart pointers
Key Takeaways
Section titled “Key Takeaways”- Smart pointers automatically manage memory
unique_ptrfor exclusive ownershipshared_ptrfor shared ownership with reference countingweak_ptrfor non-owning references to shared resources- Use
make_uniqueandmake_sharedfor efficiency
Next Steps
Section titled “Next Steps”Now let’s learn about modern C++ features that make memory management safer.
Next Chapter: 05_modern_cpp/24_auto_range_based.md - auto and Range-based for loops