Question

From boost documentation on boost::shared_ptr:

Because the implementation uses reference counting, cycles of shared_ptr instances will not be reclaimed. For example, if main() holds a shared_ptr to A, which directly or indirectly holds a shared_ptr back to A, A's use count will be 2. Destruction of the original shared_ptr will leave A dangling with a use count of 1. Use weak_ptr to "break cycles."

I could not understand this paragraph, could you provide a minimum example of this situation and explain the consequence.

Was it helpful?

Solution

How do smart pointer work? They memorize the count of the smart pointers that point to the object and increase this count when new shared pointer takes control on the object and decrease the count if the shared pointer looses control on the object.

Assume you have a class:

class A{
public:
    A(){std::cout << "Object created" << std::endl;}
    ~A(){std::cout << "Object destroyed" << std::endl;}
    void setSibling(boost::shared_ptr<A> &sibling){
        m_sibling = sibling;
    }
private:
    boots::shared_ptr<A> m_sibling;    
};

and a foo():

void foo(){
    //count increases from 0 to 1 (ptr take control on instance of A)
    boost::shared_ptr<A> ptr(new A); 

    //count increases from 1 to 2 (m_sibling take control on instanse of A)
    ptr->setSibling(ptr); 

    //count decreases from 2 to 1 
    //(ptr is destroyed and lose control on instance of A)
    return; 
}

The m_sibling will lose control when the ~A() will be called, but ~A() will be called only when all shared pointers will lose a control. So after foo was called you can't access to that instance of A. But the count is 1 and shared pointer will NOT delete that object, so you have memory and resource leak.

See the documentation for weak_ptr in boost to see how to use them with shared_ptr.

In short: weak pointer is like shared pointer but do not increase the count. If you have an instance of weak_ptr created from shared_ptr to the object that was destroyed, weak_prt instance will throw and exception (segfault won't happen) if you will try to access the raw pointer. There is an example in boost documentation how to use weak_prt correctly using weak_ptr::lock() method.

OTHER TIPS

Imagine a treasure.
Your friend takes a chest and puts some gold into. And also he makes a map.
And it is a magic map with one clause: If you burn the latest copy of the map, the treasure and the gold is gone.
Your friend puts the map into the chest right over the gold, makes second map for you and closes the chest with the first map inside.
He gives you second copy of the map and disappears with the treasure.
The question is: what happends if you burn your map?
The answer: Nothing, the treasure is still somewhere.

Why? Because the latest copy of the map is still in the chest!

Here is an example (note that the ~A is never called here):

#include <boost/shared_ptr.hpp>
#include <iostream>

using boost::shared_ptr;
struct A
{
    ~A()
    {
        std::cout << "~A()" << std::endl;
    }
    void set_shared_ptr(const shared_ptr<A> &p)
    {
        p_ = p;
    }
    shared_ptr<A> p_;
};

int main()
{
  shared_ptr<A> q(new A);
  q->set_shared_ptr(q);
  q.reset();
}

From Boost documentation

Because the implementation uses reference counting, cycles of shared_ptr instances will not be reclaimed.

You write:

I could not understand this paragraph

That's good; that's because you are smart. The paragraph makes no sense what-so-ever. If you think you get it, it implies that you don't.

Cycles cannot be reclaimed, well, because there is a cyclic dependency! No part of the cycle can be reclaimed before the rest of the cycle is reclaimed, so you would have to have every object destroyed before its destruction begins. It's part of the broken design of your program if you have cyclic dependencies. Don't try to blame smart pointers (or reference counting).

No part of the fundamental dependency issue is related in any way with the implementation details of smart pointers; it is caused by the very definition of an owning smart pointer: the owned object will not be destroyed before the destructor of the (last) owning pointer starts running.

And of course it's also true with exclusive ownership smart pointers like std::unique_ptr which don't even have a reference count!

Use weak_ptr to "break cycles."

Don't. Avoid cycles. You can't "break" a cycle. There is no such thing as "breaking" a cycle.

The documentation of Boost is worse than useless here. It's dangerous. It mixes invariant and implementation at such a level, it demonstrates a very bad understanding of the semantic of smart pointers.

And it tells a lot about the ability of fake information and anti patterns to reproduce themselves!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top