Smart Pointers: Weak Pointers

What is it?

C++ Smart Pointers std::weak_ptr is a type of smart pointer that holds a non-owning ("weak") reference to an object that is managed by std::shared_ptr. It must be converted to std::shared_ptr in order to access the object it points to. std::weak_ptr models temporary ownership: when an object needs to be accessed only if it exists, and it may be deleted at any time by other code. std::weak_ptr is used in conjunction with std::shared_ptr to break strong reference cycles which could lead to memory leaks.


Syntax

The syntax of declaring and using a std::weak_ptr is:

std::weak_ptr<T> weakPtr;

Where,

  • T is the type of the object to which the weak pointer points.
  • weakPtr is the name of the weak pointer.



How to use it

To use std::weak_ptr, follow the below steps:

  1. Declare and initialize a std::shared_ptr.
  2. Create a std::weak_ptr from the std::shared_ptr.
  3. Use the lock() method of std::weak_ptr to get a std::shared_ptr that shares ownership of the object. If the object has already been deleted, the std::shared_ptr will be empty.



Program code snippet example

#include <iostream>
#include <memory>

struct MyClass {
    int value;

    MyClass(int val) : value(val) { std::cout << "Resource acquired\n"; }
    ~MyClass() { std::cout << "Resource destroyed\n"; }
};

int main() {
    std::weak_ptr<MyClass> weakPtr;

    {
        std::shared_ptr<MyClass> sharedPtr = std::make_shared<MyClass>(20);
        weakPtr = sharedPtr;

        auto lockedPtr = weakPtr.lock(); // Get a shared_ptr
        if(lockedPtr) {
            std::cout << "Weak pointer is valid with value: " << lockedPtr->value << "\n";
        }
    }

    auto lockedPtr = weakPtr.lock(); // Get a shared_ptr
    if(!lockedPtr) {
        std::cout << "Weak pointer is expired\n";
    }

    return 0;
}

Output:

Resource acquired
Weak pointer is valid with value: 20
Resource destroyed
Weak pointer is expired



Important to know

  • std::weak_ptr does not extend the lifetime of the managed object. The object could be deleted while there are still weak pointers holding a reference to it.
  • To access the object a std::weak_ptr points to, the std::weak_ptr must be converted to a std::shared_ptr using the lock() method.
  • The lock() method returns a std::shared_ptr that shares ownership of the managed object if it has not yet been deleted, or an empty std::shared_ptr otherwise.



Best practices

When using std::weak_ptr, it is important to keep the following best practices in mind:

  1. Use std::weak_ptr to break cycles: If you have std::shared_ptr objects that point to each other, but do not need to keep each other alive, use a std::weak_ptr for one of the pointers.

  2. Always check the result of lock(): Before you use the object a std::weak_ptr points to, always

check the std::shared_ptr returned from lock(). The object may have been deleted, and not checking could lead to accessing a deleted object.

  1. Don't use std::weak_ptr to manage resources: std::weak_ptr is only meant to be a secondary reference to an object that is owned by std::shared_ptrs. It does not have the capability to manage a resource, as it does not know when to delete it.




Declare a std::weak_ptr called boss_ptr2 and assign it with the std::shared_ptr object of boss_ptr.