shared_ptr uses an additional counter object (for example, a shared counter or control unit) to store a reference counter. (BTW: this counter object also saves the debiter.)
Each shared_ptr and weak_ptr contains a pointer to the actual pointer and a second pointer to the counter object.
To implement weak_ptr , the counter object stores two different counters:
- "Use count" - the number of
shared_ptr instances pointing to the object. - "weak count" is the number of
weak_ptr instances pointing to the object, plus one if the "usage counter" is still> 0.
The pointer is deleted when the "usage counter" reaches zero.
The helper counter object is deleted when the weak counter reaches zero (which means that the usage counter must also be zero, see above).
When you try to get shared_ptr from weak_ptr , the library atomically checks the "usage count", and if it> 0 increases it. If it succeeds, you will get your shared_ptr . If the "usage counter" is already zero, you will get an empty shared_ptr instance instead.
EDIT : why do they add one to the weaker score instead of just letting go of the counter object when both values ​​fall to zero? Good question.
An alternative would be to delete the counter object when the usage counter and weak count drop to zero. Here is the first reason: checking two (indicative sizes) counters is atomically not possible on each platform, and even where it is, it is more complicated than checking only one counter.
Another reason is that the plaintiff must remain valid until it completes the execution. Since the remote object is stored in the counter object, this means that the counter object must remain valid. Think about what might happen if one object is shared_ptr and one weak_ptr for some object, and they are reset simultaneously in parallel threads. Let say that shared_ptr first. It reduces the "usage count" to zero and begins to execute the debiter. Now weak_ptr reduces the "weak count" to zero and finds that the "usage counter" is also zero. Thus, it deletes the object "counter", and with it the debiter. While the debiter is still running.
Of course, there would be different ways to ensure that the counter object remains alive, but I think that increasing the "weak count" on one is a very elegant and intuitive solution. A weak count becomes the reference count for the counter object. And since shared_ptr refers to a counter object, they must also increase the "weak count".
Probably an even more intuitive solution would be to increase the "weak score" for each individual shared_ptr , since each single shared_ptr contains a reference to the "counter" object.
Adding one for all shared_ptr instances is just an optimization (it saves one atomic increment / decrement when copying / assigning shared_ptr instances).