Search code examples
c++pointersboostshared-ptr

Appropriate use for boost::shared_ptr?


A question about boost::shared_ptr here:

I have 3 Classes.

A is some kind of Main class which is responsible to manage everything.

B is a class which just has functions to do some work.

Dispatcher is just a class which wraps around a seperate thread, which gets the work from Instaces of Bdone in this thread.

So it is kinda working like this: A has an instance of Dispatcher. Now on occassion A generates an instance of B and passes it to the dispatcher.

The important part is, that B needs to call A::callback() when it's done. This is why B gets a reference to A in it's constructor ( see code below )

A.hpp

class A : public boost::enable_shared_from_this<A>
{
public:
    A();
    void sendB();
    void callback();
private:
    Dispatcher m_Dispatcher;
};

B.hpp

class B
{
public:
    B(boost::shared_ptr<A> ptr);
    boost::shared_ptr<A> m_PointerToA;
 /* Some other functions */
};

Dispatcher.hpp

class Dispatcher
{
public:
     void run();
     void dispatch(boost::shared_ptr<B> b);
private:
     void doWork();
     boost::thread m_Thread;  
};

A.cpp

A::A()
{
    m_Dispatcher.run();
}
void A::sendB()
{
    boost::shared_ptr ptr_B;
    ptr_B.reset(new B(this->shared_from_this);
    m_Dispatcher.dispatch(ptr_B);
}

B.cpp

B::B(boost::shared_ptr<A> ptr) :
    : m_PointerToA(ptr)
{
}

main_example.cpp

int main()
{
     A instanceA;
     while(true)
     {
          instanceA.sendB();
          /* Do some other stuff */
     }
     return 0;
}

So my question is:

Is it reasonable to use boost::shared_ptr for this purpose?

I am not sure if the shared_ptr is the right thing to go here. My problem is, that I don't know what happens exactly when I call the constructor from B and pass it the this pointer. Now according to shared_ptr I would assume that m_PointerToA takes ownership of A. But this would mean that when the work in the Dispatcher is done and my instance of B gets deleted it would also delete the reference to m_PointerToA which would actually mean it kills the object itself despite the fact there is an actual instance of A in the main loop.

Update:

Added some code and updated question itself to make it more clear.


Solution

  • Yes, it is okay to just copy/assign a shared_ptr, it will only increase the reference count.

    In your example, shared_from_this() will create a (here: temporary) shared_ptr from the weak_ptr that is hold by this (ref count 1), so when you assign/copy-construct m_PointerToA, the reference count will increase temporarily to 2 before the ctor returns and the temporary object will be destroyed, decreasing the reference count to 1 again (the shared_ptr is "aware" of the one instance in your B object).

    So, yes, if B is deleted, it will destroy A in this case (as the reference count drops to 0).

    Your concern

    This would mean if my Instance of B is deleted, it would also delete m_PointerToA which would also kill my instance of A . Of course my original instance of A is held elsewhere.

    only shows that if you plan/need/intend to keep a pointer to the instance of A for further usage, you should do so with a shared_ptr as well instead of a raw pointer. If you have control of A's interface, the easiest way would be a named constructor like this:

    class A : public boost::enable_shared_from_this<A> {
        public:
            static boost::shared_ptr<A> create();
    
            void initClassB();
            // ....
        private:
            A();
            A( const A & other );
            A& operator=( const A & rhs );
    
    };
    
    boost::shared_ptr<A> A::create() {
        return boost::shared_ptr<A>( new A() );
    }
    

    Then, even if your instance of B is deleted, the instance of A will still survive because the reference count of the shared_ptr is still (at least) 1.