When is std::weak_ptr useful?

weak_ptr::lock
std::shared_ptr
weak_ptr::expired
weak_ptr from shared_ptr
weak_ptr from unique_ptr
std::weak_ptr destructor
weak_ptr nullptr
weak pointer implementation c++

I started studying smart pointers of C++11 and I don't see any useful use of std::weak_ptr. Can someone tell me when std::weak_ptr is useful/necessary?

A good example would be a cache.

For recently accessed objects, you want to keep them in memory, so you hold a strong pointer to them. Periodically, you scan the cache and decide which objects have not been accessed recently. You don't need to keep those in memory, so you get rid of the strong pointer.

But what if that object is in use and some other code holds a strong pointer to it? If the cache gets rid of its only pointer to the object, it can never find it again. So the cache keeps a weak pointer to objects that it needs to find if they happen to stay in memory.

This is exactly what a weak pointer does -- it allows you to locate an object if it's still around, but doesn't keep it around if nothing else needs it.

std::weak_ptr, 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 someone else, std::weak_ptr is used to track the object, and it is converted to std::shared_ptr to assume temporary ownership. std::weak_ptr is a very good way to solve the dangling pointer problem. By just using raw pointers it is impossible to know if the referenced data has been deallocated or not. Instead, by letting a std::shared_ptr manage the data, and supplying std::weak_ptr to users of the data, the users can check validity of the data by calling expired() or lock().

std::weak_ptr is a very good way to solve the dangling pointer problem. By just using raw pointers it is impossible to know if the referenced data has been deallocated or not. Instead, by letting a std::shared_ptr manage the data, and supplying std::weak_ptr to users of the data, the users can check validity of the data by calling expired() or lock().

You could not do this with std::shared_ptr alone, because all std::shared_ptr instances share the ownership of the data which is not removed before all instances of std::shared_ptr are removed. Here is an example of how to check for dangling pointer using lock():

#include <iostream>
#include <memory>

int main()
{
    // OLD, problem with dangling pointer
    // PROBLEM: ref will point to undefined data!

    int* ptr = new int(10);
    int* ref = ptr;
    delete ptr;

    // NEW
    // SOLUTION: check expired() or lock() to determine if pointer is valid

    // empty definition
    std::shared_ptr<int> sptr;

    // takes ownership of pointer
    sptr.reset(new int);
    *sptr = 10;

    // get pointer to data without taking ownership
    std::weak_ptr<int> weak1 = sptr;

    // deletes managed object, acquires new pointer
    sptr.reset(new int);
    *sptr = 5;

    // get pointer to new data without taking ownership
    std::weak_ptr<int> weak2 = sptr;

    // weak1 is expired!
    if(auto tmp = weak1.lock())
        std::cout << *tmp << '\n';
    else
        std::cout << "weak1 is expired\n";

    // weak2 points to new data (5)
    if(auto tmp = weak2.lock())
        std::cout << *tmp << '\n';
    else
        std::cout << "weak2 is expired\n";
}

std::weak_ptr, unique_ptr when if you want to have single ownership(Exclusive) of resource. Only one unique_ptr can point to one resource. Since there can be one unique_ptr for single resource its not possible to copy one unique_ptr to another. 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 someone else, std::weak_ptr is used to track the object, and it is converted to std::shared_ptr to assume temporary ownership.

Another answer, hopefully simpler. (for fellow googlers)

Suppose you have Team and Member objects.

Obviously it's a relationship : the Team object will have pointers to its Members. And it's likely that the members will also have a back pointer to their Team object.

Then you have a dependency cycle. If you use shared_ptr, objects will no longer be automatically freed when you abandon reference on them, because they reference each other in a cyclic way. This is a memory leak.

You break this by using weak_ptr. The "owner" typically use shared_ptr and the "owned" use a weak_ptr to its parent, and convert it temporarily to shared_ptr when it needs access to its parent.

Store a weak ptr :

weak_ptr<Parent> parentWeakPtr_ = parentSharedPtr; // automatic conversion to weak from shared

then use it when needed

shared_ptr<Parent> tempParentSharedPtr = parentWeakPtr_.lock(); // on the stack, from the weak ptr
if( !tempParentSharedPtr ) {
  // yes, it may fail if the parent was freed since we stored weak_ptr
} else {
  // do stuff
}
// tempParentSharedPtr is released when it goes out of scope

When should I use shared_ptr and unique_ptr in C++, and what are , is a 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 referenced object. The weak_ptr objects that point to a resource don't affect the resource's reference count. When the last shared_ptr object that manages that resource is destroyed, the resource will be freed, even if there are weak_ptr objects pointing to that resource. This behavior is essential for avoiding cycles in data structures.

Here's one example, given to me by @jleahy: Suppose you have a collection of tasks, executed asynchronously, and managed by an std::shared_ptr<Task>. You may want to do something with those tasks periodically, so a timer event may traverse a std::vector<std::weak_ptr<Task>> and give the tasks something to do. However, simultaneously a task may have concurrently decided that it is no longer needed and die. The timer can thus check whether the task is still alive by making a shared pointer from the weak pointer and using that shared pointer, provided it isn't null.

std::weak_ptr - cppreference.com, instances pointing to the object, plus one if the "use count" is still > 0. To better understand what weak_ptr is useful for, have a look at the following examples. One of the most useful purposes with std::weak_ptr is to avoid circular dependencies when using smart pointers. Raw pointers example. This example uses raw pointers to create a circular dependency between two objects.

They are useful with Boost.Asio when you are not guaranteed that a target object still exists when an asynchronous handler is invoked. The trick is to bind a weak_ptr into the asynchonous handler object, using std::bind or lambda captures.

void MyClass::startTimer()
{
    std::weak_ptr<MyClass> weak = shared_from_this();
    timer_.async_wait( [weak](const boost::system::error_code& ec)
    {
        auto self = weak.lock();
        if (self)
        {
            self->handleTimeout();
        }
        else
        {
            std::cout << "Target object no longer exists!\n";
        }
    } );
}

This is a variant of the self = shared_from_this() idiom often seen in Boost.Asio examples, where a pending asynchronous handler will not prolong the lifetime of the target object, yet is still safe if the target object is deleted.

How does weak_ptr work?, , that's the whole point of the system: shared_ptr is implemented (in boost or std implementations) with an atomic counter used to sync the moment when the object need to be destroyed. Once the object is destroyed, all wp. lock() calls will return null shared_ptr. expired() may be faster than use_count(). This function is inherently racy, if the managed object is shared among threads that might be creating and destroying copies of the shared_ptr : then, the result is reliable only if it matches the number of copies uniquely owned by the calling thread, or zero; any other value may become stale before it can be used.

Users - Is weak_ptr lock method thread safe?, By using a weak_ptr , you can create a shared_ptr that joins to an <algorithm> using namespace std; class Controller { public: int Num;  Because the default constructor is constexpr, static weak_ptrs are initialized as part of static non-local initialization, before any dynamic non-local initialization begins. This makes it safe to use a weak_ptr in a constructor of any static object.

How to: Create and use weak_ptr instances, std__memory__weak_ptr_expired.cpp // compile with: /EHsc #include <memory> #include <iostream> int main() { std::weak_ptr<int> wp;  When cyclic references are unavoidable, or even preferable for some reason, use weak_ptr to give one or more of the owners a weak reference to another shared_ptr. By using a weak_ptr, you can create a shared_ptr that joins to an existing set of related instances, but only if the underlying memory resource is still valid.

weak_ptr Class, std::unique_ptr was developed in C++11 as a replacement for std::auto_ptr. unique_ptr is a new facility with similar functionality, but with improved security (​no fake  marko in comments pointed the valid issue. std::weak_ptr cannot be used as a key in a way you are using it at all. Only if you can ensure that pointed value will never change nor pointer itself will never expire.

Comments
  • possible duplicate of boost, shared ptr Vs weak ptr? Which to use when?
  • So std::wake_ptr can point only where another pointer points and it points to nullptr when the object pointed is deleted/not pointed by any other pointers anymore?
  • @R.M.: Basically, yes. When you have a weak pointer, you can attempt to promote it to a strong pointer. If that object still exists (because at least one strong pointer to it exists still) that operation succeeds and gives you a strong pointer to it. If that object does not exist (because all strong pointers went away), then that operation fails (and typically you react by throwing away the weak pointer).
  • While a strong pointer keeps an object alive, a weak_ptr can look at it... without mucking with the object's life time.
  • Another example, which I've used a few times at least, is when implementing observers, it sometimes becomes convenient to have the subject maintain a list of weak pointers and do its own list cleanup. It saves a little bit of effort explicitly removing observers when they are deleted, and more significantly you don't have to have information about the subjects available when destroying observers which generally simplifies things a lot.
  • Wait, what is wrong with the cache holding a shared_ptr and just removing it from its list when it should be cleared from memory? Any users will hold a shared_ptr all the same and the cached resource will be cleared as soon as all users are done with it.
  • Ok, it's as if if you locally set a (owning) pointer to null (delete memory), all other (weak) pointers to the same memory are also set to null
  • std::weak_ptr::lock creates a new std::shared_ptr that shares ownership of the managed object.
  • How is this a memory leak? If team is destructed it will destruct its members, thus the shared_ptr ref count will be 0 and also destructed?
  • @paulm Team will not destroy "its" members. The whole point of shared_ptr is to share ownership, so no one has the particular responsibility to free the memory, it is freed automatically when no longer used. Unless there is a loop... You may have several teams sharing the same player (past teams ?). If the team object "owns" the members, then there is no need to use a shared_ptr to begin with.
  • It won't destroy them but its shared_ptr will go out of scope with it, decrements the use_count, thus at this point use_count is 0 and so the shared_ptr will delete what its pointing to?
  • @paulm You are right. But since, in this example, team is also a shared_ptr referenced by its "team members", when will it got destroyed ? What you are describing is a case where there is no loop.
  • It's not so bad, I would think. If a member can belong to many teams, using a reference won't work.
  • :Sounds like a good example but can you please elaborate you example a bit more? I am thinking when a task is finished, it's should already been removed from the std::vector<std::weak_ptr<Task>> without a periodic check. So not sure if the std::vector<std::weak_ptr<>> is very helpful here.