I am reading Scott Meyers "Effective C++" book. It was mentioned that there are tr1::shared_ptr
and tr1::weak_ptr
act like built-in pointers, but they keep track of how many tr1::shared_ptrs
point to an object.
This is known as reference counting. This works well in preventing resource leaks in acyclic data structures, but if two or more objects contain tr1::shared_ptrs
such that a cycle is formed, the cycle may keep each other's reference count above zero, even when all external pointers to the cycle have been destroyed.
That's where tr1::weak_ptrs
come in.
My question is how cyclic data structures make the reference count above zero. I kindly request an example C++ program. How is the problem solved by weak_ptrs
? (again, with example please).
Let me repeat your question: "My question, how cyclic data structures makes reference count above zero, kindly request to show with example in C++ program. How the problem is solved by
weak_ptrs
again with example please."The problem occurs with C++ code like this (conceptually):
To answer the second part of your question: It is mathematically impossible for reference counting to deal with cycles. Therefore, a
weak_ptr
(which is basically just a stripped down version ofshared_ptr
) cannot be used to solve the cycle problem - the programmer is solving the cycle problem.To solve it, the programmer needs to be aware of the ownership relationship among the objects, or needs to invent an ownership relationship if no such ownership exists naturally.
The above C++ code can be changed so that A owns B:
A crucial question is: Can
weak_ptr
be used in case the programmer cannot tell the ownership relationship and cannot establish any static ownership because of lack of privilege or lack of information?The answer is: If ownership among objects is unclear,
weak_ptr
cannot help. If there is a cycle, the programmer has to find it and break it. An alternative remedy is to use a programming language with full garbage collection (such as: Java, C#, Go, Haskell), or to use a conservative (=imperfect) garbage collector which works with C/C++ (such as: Boehm GC).All the above answer are WRONG.
weak_ptr
is NOT used to break cyclic references, they have another purpose.Basically, if all
shared_ptr(s)
were created bymake_shared()
orallocate_shared()
calls, you will NEVER needweak_ptr
if you have no resource other than memory to manage. These functions create theshared_ptr
reference counter object with the object itself, and the memory will be freed at the same time.The only difference between
weak_ptr
andshared_ptr
is that theweak_ptr
allows the reference counter object to be kept after the actual object was freed. As a result, if you keep a lot ofshared_ptr
in astd::set
the actual objects will occupy a lot of memory if they are big enough. This problem can be solved by usingweak_ptr
instead. In this case, you have to ensure theweak_ptr
stored in the container is not expired before using it.A
shared_ptr
wraps a reference counting mechanism around a raw pointer. So for each instance of theshared_ptr
the reference count is increased by one. If twoshare_ptr
objects refer the eachother they will never get deleted because they will never end up with a reference count of zero.weak_ptr
points to ashared_ptr
but does not increase its reference count.This means that the underying object can still be deleted even though there is aweak_ptr
reference to it.The way that this works is that the
weak_ptr
can be use to create ashared_ptr
for whenever one wants to use the underlying object. If however the object has already been deleted then an empty instance of ashared_ptr
is returned. Since the reference count on the underlying object is not increased with aweak_ptr
reference, a circular reference will not result in the underlying object not being deleted.For future readers.
Just want to point out that explanation given by Atom is excellent, here is working code
Weak pointers just "observe" the managed object; they don't "keep it alive" or affect its lifetime. Unlike
shared_ptr
, when the lastweak_ptr
goes out of scope or disappears, the pointed-to object can still exist because theweak_ptr
does not affect the lifetime of the object - it has no ownership rights. Theweak_ptr
can be used to determine whether the object exists, and to provide ashared_ptr
that can be used to refer to it.The definition of
weak_ptr
is designed to make it relatively foolproof, so as a result there is very little you can do directly with aweak_ptr
. For example, you can't dereference it; neitheroperator*
noroperator->
is defined for aweak_ptr
. You can't access the pointer to the object with it - there is noget()
function. There is a comparison function defined so that you can storeweak_ptrs
in an ordered container, but that's all.