Question

When you wish to make an access using a weak pointer, you are first advised to get a strong pointer to the pointed object by locking. Locking may not succeed in case the pointed object was deleted earlier.

It seems to me that unless you did something wrong in breaking the cycles to decide what is a weak pointer, locking will succeed. So you are locking just to cross-check your design.

Is this correct?

I have seen some remarks about caching, but they seem like an abuse of weak_ptrs. But of course one man's abuse is another man's innovation. I would like to hear opinions.

Was it helpful?

Solution

If you're using weak_ptr only to break cycles, then yes, getting a shared_ptr from it should always succeed.

But that's not the only use. Matthieu M. gives one example of using them.

You mention caching and that's a good use case for weak_ptr where there are no cycles, and I don't consider it an abuse at all. If you have an object that some other part of the system (another thread, or a cache) owns and you want to store a reference to that object for possible later use, if you use a shared_ptr to refer to the object then you share ownership of it and will prolong its lifetime. If you are not sure you'll need the object later so don't want to prolong its lifetime you could use a weak_ptr and check if it still exists when you need it. If it doesn't exist you find a different object or create it again (which might be slow e.g. require a database query, which is why you wanted to reuse an existing object if possible.)

OTHER TIPS

No, you should not.

Suppose you maintain a list of observers, upon destruction you would need to unsubscribe the observer from the object(s) it was observing, however that requires that the observer maintains a list of the entities it observes, leading to a cycle.

To simplify the design, it is simpler to introduce a level of indirection. A broker between the observer and the entity will allow the observer to be destroyed and the entity querying for its liveness.

How to ? Simply you can allocate a std::shared_ptr<Observer> and have an entity only retain a std::weak_ptr<Observer>, then when an entity iterate over its list of observers, it can cull the references to those who died since the last iteration.

Rather than thinking of it as "locking", bear in mind that all you do is obtain another share in the ownership. The weak pointer itself doesn't own anything, so it can't be used directly.

The typical use for weak pointers probably lies in concurrent code. Suppose you have a collection of objects owned by shared pointers somewhere. You can then have another collection of weak pointers referring to those same objects (e.g. a collection of timers). A second thread may pick up the weak pointer, attempt to create a shared pointer from it, and upon success call, say, a timer routine on the object. If the task has already died at the time, then the shared pointer will be null and the second thread skips the task.

The crucial fact about std::shared_ptr is that its internal reference count is updated atomically, and so you can write code in the way I described and it will be race-free.

Thread 1                          Thread 2
--------                          --------
std::set<std::shared_ptr<Task>>   std::list<std::weak_ptr<Task>> todo;
add
remove                            for (auto wp : todo)
                                      if (auto p = wp.lock())
                                          p->do_work();

The use case where you have a weak_ptr which is invalid seems like a race condition/bad design.

weak_ptr should be used for accessing objects with strict life time, which the accessing object doesn't hold ownership

If you have an object with non-strict life time, you should use shared_ptr.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top