boost::shared_ptr has become one of the most versatile smart_pointer structures used in C++. If you consistently use shared_ptr to refer to objects, you don’t have to worry when to destroy them. We would like to see how boost::shared_ptr can be used amidst up-casting and down-casting across class hierarchies.

Consider the following class.

    class A
     {
     public:
             A():m_i(0){}
             virtual ~A(){}
             int m_i;
     };

If we always use boost::shared_ptr-s to refer to an instance of A, we can use them across scopes, worry free of when to destroy them as shown.

    using namespace boost;

    shared_ptr  <A>   sA1;
    {
         shared_ptr <A> sA2( new A);
         sA1 = sA2;
         //sA1 and sA2 shares the same pointer to A
         //and the same reference counting structure
         assert( sA1.use_count() == sA2.use_count() );
         assert( sA1.use_count() == 2);
    }
    assert( sA1.use_count() == 1);

Now, let B, be a derived class of A as shown below.

</pre> class B : public A { public: B():m_j(0){} ~B(){} int m_j; }; </pre>

shared_ptr and up-casting

If we assign a shared_ptr B to a shared_ptr A, the two shared pointers still share the same pointer and the reference count. So shared_pointer respects up-casting. Please see the code below.

    using namespace boost;

    shared_ptr  <A>   sA;
    {
         shared_ptr <B> sB( new B);
         sA = sB;
         //sA and sB shares the same pointer to B
         //and the same reference counting structure
         assert( sA.use_count() == sB.use_count() );
         assert( sA.use_count() == 2);
    }
    assert( sA.use_count() == 1);

shared_ptr and down-casting

Now consider the problem of down-casting.

    using namespace boost;

    shared_ptr  <B>   sB;
    {
         shared_ptr <A> sA( new B);
         //how can we reset sB with the pointer
         //now owned by sA.?
    }

The following wont compile.

    using namespace boost;

    shared_ptr  <B>   sB;
    {
         shared_ptr <A> sA( new B);
         //compilation error in the line below
         sB = sA;
    }

Here is another wrong way, that results in run-time error.

    using namespace boost;

    shared_ptr  <B>   sB;
    {
         shared_ptr <A> sA( new B);
         B * pB = dynamic_cast <B*> (sA.get());
         sB.reset( pB );
         //though sA and sB now points to the same
         //instance of B, they are reference counted
         //using different structures.
         assert( sA.use_count() == 1);
         assert( sB.use_count() ==1);
    }
    //Instance of B pointed to by sA is destroyed.
    //But hey, sB still refers to it.
    //Now, the following will cause a runtime error
    //due to double deletion
    sB.reset();

The correct way is shown below.

    using namespace boost;

    shared_ptr  <B>   sB;
    {
         shared_ptr <A> sA( new B);
         sB = dynamic_pointer_cast <B,A> ( sA ) ;
         //sA and sB now shares the same instance of B.
         //Further sA and sB shares the same reference
         //counting structure.
         assert( sA.use_count() == 2);
         assert( sB.use_count() == 2);
    }
    assert( sB.use_count() == 1);


blog comments powered by Disqus