I understand how a shared_ptr works except for the role of the weak_ptr. I understand its there to detect circular references when the reference count isn't zero, but beyond this I don't understand just exactly how it does this. What does it do?

- 8,038
- 2
- 40
- 58

- 29,025
- 43
- 182
- 361
-
possible duplicate of [shared\_ptr and weak\_ptr differences](http://stackoverflow.com/questions/4984381/shared-ptr-and-weak-ptr-differences) – Peter Clark Aug 09 '14 at 22:23
-
3No, weak pointers are very rarely useful for resolving circular references. They're much more useful for other things. – Kerrek SB Aug 09 '14 at 22:23
-
1@PeterClark I cannot understand the answer from that Q, the part about weak_ptrs is not very coherent. – user997112 Aug 09 '14 at 22:25
-
1Usually shared_ptr are good store some shared information somewhere in standard container while using weak_ptr to pass parameter in function calls. – Tanuki Aug 09 '14 at 22:28
-
@user997112 Sorry, didn't see your reply to me. I think the general practice is to comment on the answer if you're commenting about it (not sure if it notifies me if you do it on the question itself and I haven't commented on the question). Is there anything in particular that is confusing? One thing to clarify - are you looking for **how** weak_ptr works, or **why** you would use it? I answer the second one (which is what your title implies), but you the body of your question sounds like you might be looking for the first. – Peter Clark Sep 12 '14 at 03:38
-
@Tanuki "_while using weak_ptr to pass parameter in function calls_" Why would you ever want to do that?!! – curiousguy Jun 11 '16 at 00:31
2 Answers
See also: When is std::weak_ptr useful? for why and How does weak_ptr work? for how.
I'll provide an example of how I've seen it used, though the sample code I whipped up is a bit convoluted so bear with me:
#include <vector>
#include <memory>
#include <ostream>
int main()
{
// Fill container with values 1-50. This container OWNS these values.
std::vector<std::shared_ptr<int>> owning_container;
for(int i = 1; i <= 50; ++i)
{
owning_container.emplace_back(std::make_shared<int>(i));
}
// Create a sepearate container that references all owned values that are multiples of 5.
std::vector<std::weak_ptr<int>> referencing_container;
for(std::shared_ptr<int> const& i : owning_container)
{
if((*i) % 5 == 0)
{
// Make weak_ptr that references shared_ptr
referencing_container.emplace_back(i);
}
}
// Go through the owned values and delete all that are multiples of 10.
for(auto it = owning_container.begin(); it != owning_container.end();)
{
std::shared_ptr<int> const& i = *it;
if(*i % 10 == 0)
{
it = owning_container.erase(it);
}
else
{
++it;
}
}
// Now go through the referencing container and print out all values.
// If we were dealing with raw pointers in both containers here we would access deleted memory,
// since some of the the actual resources (in owning_container) that referencing_container
// references have been removed.
for(std::weak_ptr<int> const& i_ref : referencing_container)
{
// Check if the shared resource still exists before using it (purpose of weak_ptr)
std::shared_ptr<int> i = i_ref.lock();
if(i)
{
std::cout << *i << std::endl;
}
}
return 0;
}
Here we have a container that contains some shared resource - ints in this case - (shared_ptr
), that another container needs to reference (weak_ptr
). The referencing does not own the resource, it only needs to be able to access it if it exists. In order to tell if the resource being referenced is still alive, we convert the weak_ptr
to a shared_ptr
using weak_ptr::lock()
. Those resources that still exist will have a valid shared_ptr
returned by lock()
. Those that no longer exist will return a null shared_ptr
. shared_ptr
has an operator bool()
that we can use to check if it is null or not before attempting to use it.
A less convoluted scenario might be if you were making a game where every object in the game was represented by a game_object
. Say you have some kind of seeking logic for an enemy which requires a target game_object
to seek to. Using the above, you could have the enemy hold onto a weak_ptr<game_object>
. It doesn't own this game_object
. If something else kills its target, its target should die; not hang in some limbo state which would happen if the enemy held a shared_ptr
instead. This way if the enemy's target is still alive (which it can check by locking the weak_ptr
), it can execute the seeking logic; otherwise it can find a new target. The "owner" of the game_object
could be some sort of game_world
class - this would have a container of shared_ptr<game_object>
. When the enemy needs a new target it could search through this container and create its weak_ptr
from the game_world
's shared_ptr
.

- 1
- 1

- 2,863
- 3
- 23
- 37
Weak pointers don't claim ownership of a resource, but only refer to it. Thus, they don't allow you to operate on a resource in any way except claiming the ownership once again (with the weak_ptr::lock()
method). IMHO, the most frequent real-life situations where such a behaviour is desires are cyclic dependencies and (less frequently) caching.
Cyclic dependencies made with shared pointers only are de facto memory leaks, because mutual reference counts of the pointers will never be less than 1: if nothing else owns A, then B still does, and vice versa. A weak pointer doesn't 'detect' this situation. It just won't let the trouble in, simply by breaking the loop of ownership. You might still 'connect the ends of the chain' by locking the weak pointer, but none of the shared pointers that you might obtain via the weak one will persist.
The problem with caching is, yet again, that a cache usually shouldn't affect lifetime of the cached content, it is not a duty of the cache. But, if the cache would hold shared pointers, then you wouldn't be able to terminate the lifetime of a cached object without having to talk to the cache, which is often inconvenient.

- 5,160
- 1
- 27
- 49
-
Can you provide examples of cyclic dependency cases where a weak reference helped? – curiousguy Jun 11 '16 at 00:41