In one episode (35:00) of Advanced STL series, Stephan T Lavavej showed that _Weaks
, the counter whose value of 0 determines when to delete the _Ref_count
structure, equals the number of alive weak_ptr
, plus 1 if there are alive shared_ptrs
. He explained that it is necessary because of thread safety: if _Weaks
only equaled the number of weak_ptr
then when last weak_ptr
would go out of scope it would be also necessary to check _Uses
, the counter of alive shared_ptr
s, to check if _Ref_count
can be deleted. And this is unacceptable because of lack of atomicity.
Assuming that _Uses
= number of alive shared_ptr
s, _Weaks
= number of alive weak_ptr
s, imagine we have the following scenario:
(_Uses
= 0, _Weaks
= 1): last weak_ptr
goes out of scope, decrement _Weaks
(_Uses
= 0, _Weaks
= 0): if _Uses
is equal to 0, delete _Ref_count
structure
What, in multithreaded application, can go wrong, which forces us to use _Weak
= number of alive weak_ptr
+ (number of shared_ptr
? 1 : 0) implementation?
shared_ptr are noticeably slower than raw pointers. That's why they should only be used if you actually need shared ownership semantics. Otherwise, there are several other smart pointer types available. scoped_ptr and auto_ptr (C++03) or unique_ptr (C++0x) both have their uses.
The smart pointer has an internal counter which is decreased each time that a std::shared_ptr , pointing to the same resource, goes out of scope – this technique is called reference counting. When the last shared pointer is destroyed, the counter goes to zero, and the memory is deallocated.
std::shared_ptr is a smart pointer that retains shared ownership of an object through a pointer.
By moving the shared_ptr instead of copying it, we "steal" the atomic reference count and we nullify the other shared_ptr . "stealing" the reference count is not atomic, and it is hundred times faster than copying the shared_ptr (and causing atomic reference increment or decrement).
When a weak_ptr is created from a shared_ptr, it refers to the same control block but does not share the ownership of the managed object. It is not possible to directly access the managed object through a weak_ptr.
The C++11 std::shared_ptr<T> is a shared ownership smart pointer type. Several shared_ptr instances can share the management of an object's lifetime through a common control block. The managed object is deleted when the last owning shared_ptr is destroyed (or is made to point to another object).
In a typical implementation, a shared_ptr contains only two pointers: a raw pointer to the managed object that is returned by get (), and a pointer to the control block. A shared_ptr control block at least includes a pointer to the managed object or the object itself, a reference counter, and a weak counter.
The reference count increases as a new shared_ptr is constructed, and it decreases as an owning shared_ptr is destroyed. One exception to that is the reference count is left unchanged when a shared_ptr is moved because the move-constructor transfers the ownership from the source to the newly constructed shared_ptr.
Imagine the following scenario. Thread A holds a shared_ptr
, thread B holds a corresponding weak_ptr
. So in your implementation, we have _Uses == 1
and _Weaks == 1
.
There are two possible implementations for the smart pointer destructors, both with problems.
B's weak_ptr
is destroyed. Decrements _Weaks
. We have _Uses == 1
, _Weaks == 0
. B prepares to check _Uses
, but ...
Context switch.
A's shared_ptr
is destroyed. Decrements _Uses
. We have _Uses == 0
, _Weaks == 0
. Begin destruction of _Ref_count
.
Context switch.
B now get round to checking _Uses
. It's 0. Begin destruction of _Ref_count
.
Both threads are now in the process of destroying _Ref_count
. Not good.
B's weak_ptr
is destroyed. Check _Uses
. It's 1, no destruction will happen. B prepares to decrement _Weaks
, but ...
Contex switch.
A's shared_ptr
is destroyed. Checks _Weaks
. It's 1, no destruction will happen. Decrement _Uses
. We have _Uses == 0
, _Weaks == 1
. Done.
Context switch.
B now gets round to decrement _Weaks
. We have _Uses == 0
, _Weaks == 0
. Nothing else to do.
We have leaked the _Ref_count
. Not good.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With