CodeNebula
C++11coreintermediate

std::weak_ptr (C++11 Addition)

C++11 · Modern Revolution · Compiler flag: -std=c++11

Explanation

Non-owning reference to a `shared_ptr` resource, prevents circular references.

Real-World Scenario

Break circular references in a resource manager.

Quick Snippet

snippet.cpp
#include <memory> std::weak_ptr<int> wptr;

Full Example

weak_ptr.cpp
// CodeNebula - C++11 Example: std::weak_ptr
// Compile: g++ -std=c++11 -Wall -Wextra -o example weak_ptr.cpp
//
// This example demonstrates:
// - std::weak_ptr for non-owning references to shared objects
// - Breaking circular references that cause memory leaks
// - lock() to safely obtain a shared_ptr from weak_ptr
// - expired() to check if the referenced object still exists
// - Observer pattern using weak_ptr

#include <iostream>
#include <memory>
#include <string>
#include <vector>

// ============================================================
// 1. Circular reference problem (solved by weak_ptr)
// ============================================================
class Person {
    std::string name_;
public:
    // Using weak_ptr to break the cycle
    std::weak_ptr<Person> bestFriend;

    Person(const std::string& name) : name_(name) {
        std::cout << "  Person \"" << name_ << "\" created" << std::endl;
    }

    ~Person() {
        std::cout << "  Person \"" << name_ << "\" destroyed" << std::endl;
    }

    void greet() const {
        std::cout << "  " << name_ << " says hello";
        if (auto f = bestFriend.lock()) {
            std::cout << " (best friend exists)";
        } else {
            std::cout << " (best friend gone)";
        }
        std::cout << std::endl;
    }

    const std::string& name() const { return name_; }
};

// ============================================================
// 2. Cache using weak_ptr
// ============================================================
class ResourceCache {
    std::vector<std::weak_ptr<std::string>> cache_;
public:
    void store(std::shared_ptr<std::string> resource) {
        cache_.push_back(resource);  // Only stores weak reference
    }

    void printAvailable() const {
        std::cout << "  Cache contents:" << std::endl;
        int alive = 0, expired = 0;
        for (const auto& weak : cache_) {
            if (auto sp = weak.lock()) {
                std::cout << "    alive: \"" << *sp << "\"" << std::endl;
                ++alive;
            } else {
                ++expired;
            }
        }
        std::cout << "    (" << alive << " alive, " << expired << " expired)" << std::endl;
    }
};

// ============================================================
// 3. Observer pattern with weak_ptr
// ============================================================
class EventSource {
    std::vector<std::weak_ptr<std::string>> observers_;
public:
    void addObserver(std::shared_ptr<std::string> obs) {
        observers_.push_back(obs);
    }

    void notify(const std::string& event) {
        std::cout << "  Notifying observers of: " << event << std::endl;
        for (auto& weak : observers_) {
            if (auto obs = weak.lock()) {
                std::cout << "    -> " << *obs << " received event" << std::endl;
            } else {
                std::cout << "    -> (observer expired)" << std::endl;
            }
        }
    }
};

int main() {
    std::cout << "=== std::weak_ptr ===" << std::endl;

    // Breaking circular references
    std::cout << "\n--- Breaking circular references ---" << std::endl;
    {
        auto alice = std::make_shared<Person>("Alice");
        auto bob = std::make_shared<Person>("Bob");

        alice->bestFriend = bob;
        bob->bestFriend = alice;

        std::cout << "  alice use_count: " << alice.use_count() << std::endl;
        std::cout << "  bob use_count: " << bob.use_count() << std::endl;

        alice->greet();
        bob->greet();
    }
    std::cout << "  Both destroyed (no leak!)" << std::endl;

    // lock() and expired()
    std::cout << "\n--- lock() and expired() ---" << std::endl;
    std::weak_ptr<int> weak;
    {
        auto shared = std::make_shared<int>(42);
        weak = shared;

        std::cout << "  expired: " << weak.expired() << std::endl;
        std::cout << "  use_count: " << weak.use_count() << std::endl;

        if (auto locked = weak.lock()) {
            std::cout << "  Locked value: " << *locked << std::endl;
        }
    }
    std::cout << "  After shared destroyed:" << std::endl;
    std::cout << "  expired: " << weak.expired() << std::endl;
    if (auto locked = weak.lock()) {
        std::cout << "  Value: " << *locked << std::endl;
    } else {
        std::cout << "  lock() returned nullptr (object gone)" << std::endl;
    }

    // Cache pattern
    std::cout << "\n--- Cache pattern ---" << std::endl;
    ResourceCache cache;
    auto res1 = std::make_shared<std::string>("Resource A");
    auto res2 = std::make_shared<std::string>("Resource B");
    auto res3 = std::make_shared<std::string>("Resource C");

    cache.store(res1);
    cache.store(res2);
    cache.store(res3);

    cache.printAvailable();

    res2.reset();  // Release Resource B
    std::cout << "  After releasing Resource B:" << std::endl;
    cache.printAvailable();

    // Observer pattern
    std::cout << "\n--- Observer pattern ---" << std::endl;
    EventSource source;
    auto obs1 = std::make_shared<std::string>("Logger");
    auto obs2 = std::make_shared<std::string>("UI");
    auto obs3 = std::make_shared<std::string>("Metrics");

    source.addObserver(obs1);
    source.addObserver(obs2);
    source.addObserver(obs3);

    source.notify("startup");

    obs2.reset();  // UI observer destroyed
    std::cout << "  After UI observer destroyed:" << std::endl;
    source.notify("shutdown");

    return 0;
}

// Expected output:
// === std::weak_ptr ===
//
// --- Breaking circular references ---
//   Person "Alice" created
//   Person "Bob" created
//   alice use_count: 1
//   bob use_count: 1
//   Alice says hello (best friend exists)
//   Bob says hello (best friend exists)
//   Person "Bob" destroyed
//   Person "Alice" destroyed
//   Both destroyed (no leak!)
//
// --- lock() and expired() ---
//   expired: 0
//   use_count: 1
//   Locked value: 42
//   After shared destroyed:
//   expired: 1
//   lock() returned nullptr (object gone)
//
// --- Cache pattern ---
//   Cache contents:
//     alive: "Resource A"
//     alive: "Resource B"
//     alive: "Resource C"
//     (3 alive, 0 expired)
//   After releasing Resource B:
//   Cache contents:
//     alive: "Resource A"
//     alive: "Resource C"
//     (2 alive, 1 expired)
//
// --- Observer pattern ---
//   Notifying observers of: startup
//     -> Logger received event
//     -> UI received event
//     -> Metrics received event
//   After UI observer destroyed:
//   Notifying observers of: shutdown
//     -> Logger received event
//     -> (observer expired)
//     -> Metrics received event
Run command
g++ -std=c++11 -Wall -Wextra -o example weak_ptr.cpp