I tried to understand the principle behind weak_ptr's implementation, especially about ref-counting.
The cppreference https://en.cppreference.com/w/cpp/memory/weak_ptr says weak_ptr works as an observer of shared_ptr, declaring weak_ptr doesn't change the use_count of original shared_ptr. Then my question is, how is weak_ptr implemented to know the use_count of original shared_ptr. I guess weak_ptr will hold a integer pointer to shared_ptr's use_count.
I had a quick test:
using namespace std;
int main()
{
auto sp = make_shared<int>(10);
weak_ptr<int> wp(sp);
cout << wp.use_count() << endl; // 1
sp.reset(new int{5});
cout << wp.use_count() << endl; // 0
auto swp = wp.lock();
cout << swp.get() << endl; // 0
cout << *swp << endl;
return 0;
}
As you could see the result of my program, as comments. So
(1) If weak_ptr doesn't hold an integer pointer to shared_ptr's use_count, then , how does it know the use_count() should change from 1 to 0 when I called sp.reset(new int[5]). How could it know?
(2) If it holds such a pointer, when original shared_ptr came to end of lifecycle and destroyed, this pointer will point to a non-exist position! Dangling pointer!
Thus it seems to me a contradictory about how to implement weak_ptr.
Would you give some hints? Thanks a lot.
Take one implementation and observe it. For example on libstdc++ the class
__weak_ptrcontains https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/shared_ptr_base.h#L1974 the pointer to memory and the counter:Where
__weak_countcontains a pointer to the counter:Where
_Sp_counted_baseactually holds the counters:Not if the count itself is dynamically allocated! From https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/shared_ptr_base.h#L913
__shared_countallocates_Sp_counted_ptron construction dynamically:Where
_Sp_counted_ptris dynamically allocated, and it holds the pointer to memory and the counters by inheriting from_Sp_counted_base: