2

I was trying to write a caption for this question for like 10 minutes and as you will see I eventually failed. [Editor's note: I think I have fixed that.]

I was reading Herb Sutter's blog and the topic is using std::make_shared and its cons and pros. Please see the photo attached:

enter image description here

This is a small part of a very very interesting article which I highly recommend people read. My question is regarding this sentence:

A “weak reference” count to track the number of weak_ptrs currently observing the object. The shared housekeeping control block is destroyed and deallocated (and the shared object is deallocated if it was not already) when the last weak reference goes away.**

I don't really understand this statement. Initially when we create a std::shared_ptr by make_shared e.g. auto sp1 = make_shared<widget>();, there are no weak ptrs currently observing the sp1, so it will be deleted when the shared_ptr goes out of scope in the usual way.

So how does adding a weak reference change this behaviour? Can anyone explain this to me please?

Paul Sanders
  • 24,133
  • 4
  • 26
  • 48
Eduard Rostomyan
  • 7,050
  • 2
  • 37
  • 76
  • 4
    The second item is subordinate to the first: first you need all shared references to have gone away before you do anything at all. *Then* you also wait for weak references to go away before you deallocate the control block. – Kerrek SB Jun 12 '18 at 14:06
  • So the dealocation of control block caused by weak_count == 0 is only after the source was already deleted and strong_count is 0?? @KerrekSB – Eduard Rostomyan Jun 12 '18 at 14:08
  • 4
    What exactly are you asking? If the strong count is non-zero, obviously neither the shared object nor the control block can be deallocated. – Praetorian Jun 12 '18 at 14:29
  • Thanks @Praetorian, thats what I was asking! – Eduard Rostomyan Jun 12 '18 at 14:37
  • 3
    @EduardRostomyan: Yes. When the strong count reaches 0, the owned object is destroyed, and no further shares can be taken out. *Then*, once the weak pointer count reaches 0, the control block is destroyed. If there are no weak pointers, the two events coincide. – Kerrek SB Jun 12 '18 at 21:13

2 Answers2

5

The control block keeps track of all the weak_ptr references as well as the shared_ptr references. After all, the weak_ptr needs to look somewhere to see if the object is still valid.

Hence, the control block cannot be de-allocated until all shared_ptrs and all weak_ptrs have been destroyed. If you use make_shared the control block and the object are allocated together, which is mostly an optimization, except if the object is outlived by any weak_ptrs.

ravnsgaard
  • 922
  • 1
  • 10
  • 20
  • 2
    *"If you use make_shared the control block and the object are allocated together, which is mostly an optimization, except if the object is outlived by any weak_ptrs."* - Just want to point out that even if the allocated memory containing both the control block and the object is not deallocated before all shared/weak pointers, the object is likely destroyed after with the last shared pointer. – Holt Jun 12 '18 at 14:50
  • 1
    @holt Yes indeed, the destructor will be called, but the memory will not be allocated. Good point, though. – ravnsgaard Jun 12 '18 at 14:54
2

Simply put, a shared_ptr owns the managed object and the meta information (the control block) and a weak_ptr owns only the meta information.

Ownership means that:

  • when a resource has an owner, it isn't destroyed (or "freed" in the way determined when the owning "smart pointer" was constructed);
  • when the lifetime of all owners have ended, the ressource is destroyed/freed.

The reference counting part is an implementation detail. (You could have a linked list if you love very inefficient implementations with a mutex instead of relatively efficient atomic counters.)

curiousguy
  • 8,038
  • 2
  • 40
  • 58