0
0
CppHow-ToBeginner · 4 min read

How to Use weak_ptr in C++: Syntax, Example, and Tips

In C++, weak_ptr is used to hold a non-owning reference to an object managed by shared_ptr. It helps avoid circular references by not increasing the reference count. You create a weak_ptr from a shared_ptr and use lock() to access the object safely.
📐

Syntax

The weak_ptr is declared as std::weak_ptr<T>, where T is the type of the object. You initialize it from a shared_ptr. To access the object, call lock() which returns a shared_ptr if the object still exists, or an empty shared_ptr if it was deleted.

  • std::weak_ptr<T> wptr; - declares a weak pointer.
  • wptr = shared_ptr; - assign from shared pointer.
  • auto sptr = wptr.lock(); - get shared pointer safely.
cpp
std::weak_ptr<T> wptr;  // declare weak_ptr
wptr = shared_ptr;       // assign from shared_ptr
if (auto sptr = wptr.lock()) {
    // use sptr safely
} else {
    // object no longer exists
}
💻

Example

This example shows how weak_ptr can observe an object managed by shared_ptr without owning it. When the last shared_ptr is destroyed, the object is deleted and weak_ptr::lock() returns empty.

cpp
#include <iostream>
#include <memory>

int main() {
    std::shared_ptr<int> sptr = std::make_shared<int>(42);
    std::weak_ptr<int> wptr = sptr;  // weak_ptr observes sptr

    std::cout << "Shared pointer count: " << sptr.use_count() << "\n";

    if (auto locked = wptr.lock()) {
        std::cout << "Value via weak_ptr: " << *locked << "\n";
    } else {
        std::cout << "Object no longer exists.\n";
    }

    sptr.reset();  // destroy shared_ptr, object deleted

    if (auto locked = wptr.lock()) {
        std::cout << "Value via weak_ptr: " << *locked << "\n";
    } else {
        std::cout << "Object no longer exists after reset.\n";
    }

    return 0;
}
Output
Shared pointer count: 1 Value via weak_ptr: 42 Object no longer exists after reset.
⚠️

Common Pitfalls

Common mistakes when using weak_ptr include:

  • Trying to dereference weak_ptr directly without calling lock(), which is invalid.
  • Not checking if lock() returns a valid shared_ptr before use, leading to crashes.
  • Using weak_ptr when ownership is needed; it does not keep the object alive.

Always use lock() and check the result before accessing the object.

cpp
std::weak_ptr<int> wptr;
// Wrong: dereferencing weak_ptr directly
// std::cout << *wptr << std::endl; // ERROR

// Right way:
auto sptr = wptr.lock();
if (sptr) {
    std::cout << *sptr << std::endl;
} else {
    std::cout << "Object expired" << std::endl;
}
📊

Quick Reference

  • std::weak_ptr<T>: Non-owning smart pointer to T.
  • lock(): Returns shared_ptr<T> if object exists, else empty.
  • use_count(): Returns number of shared_ptr owners.
  • Use weak_ptr to break circular references.

Key Takeaways

Use std::weak_ptr to hold a non-owning reference to a shared object without increasing its reference count.
Always call lock() on weak_ptr and check if the returned shared_ptr is valid before accessing the object.
weak_ptr helps prevent memory leaks caused by circular references between shared_ptrs.
Do not dereference weak_ptr directly; it does not own the object and may be expired.
Resetting all shared_ptr owners deletes the object, making weak_ptr expired.