Considering the following code:
#include <memory>
#include <iostream>
using namespace std;
struct MySharedStruct
{
int i;
};
void print_value_of_i(weak_ptr<MySharedStruct> weakPtr)
{
if (shared_ptr<MySharedStruct> sp = weakPtr.lock())
{ cout << "Value of i = " << sp->i << endl; }
else
{ cout << "Resource has expired"; }
}
int main()
{
shared_ptr<MySharedStruct> sharedPtr(new MySharedStruct() );
sharedPtr->i = 5;
weak_ptr<MySharedStruct> weakPtr;
weakPtr = sharedPtr;
print_value_of_i(weakPtr);
sharedPtr.reset(new MySharedStruct() ); // <<----- How does weak_ptr know it has expired after this line executes?
sharedPtr->i = 10;
print_value_of_i(weakPtr);
return 0;
}
How does the weak_ptr know it has expired considering the resource that shared_ptr was referencing has been essentially replaced by another resource? What does weak_ptr keep track of to know for sure that the old shared resource was destroyed and replaced by the new shared resource? Example definitions (if relevant) of methods such lock in weak_ptr would be appreciated.
The control block allocated when a
shared_ptris created from a plain pointer contains both the reference counter for the object and the pointer to the object itself and the custom deleter object if any. When that reference counter reaches zero the object is released and the pointer is set to null. So, when the object reference counter is zero it means that the object is gone.For x86 and x86-64 they use atomic operations and no explicit locking (no mutex or spinlock). The trick of the implementation is a special lock-free (code language for busy spin) function
atomic_conditional_incrementthat only increments the object reference counter if it is not zero. It is used in the implementation ofweak_ptr::lockfunction to cope with a race when more than one thread tries to create ashared_ptrfrom the sameweak_ptrwith object reference counter being zero. See http://www.boost.org/doc/libs/1_52_0/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hppThe control block itself is shared between
shared_ptr‘s andweak_ptr‘s and has another reference counter for itself, so that it stays alive till the last reference to it is released.When a
shared_ptris reassigned it points to another control block, so that a control block only ever points to one same object. In other words, there is no replacement of one object with another in the control block.