
What are one's options when the code one is working on contains a circular dependency and one is trying to update it to use a shared_ptr vs a raw pointer? I don't think I can easily get rid of the preexisting circular dependency. The original author has created an inheritance where the base needs the derived. We all know this is wrong, but it would take quite a bit to analyze how it is used and be removed. Am I out of luck? Fictitious Example (best minimal example including the problems the preexisting code has): // File MasterClient.h #include "BaseClient.h" #include <set> class MasterClient : BaseClient { public: // Constructor adds this to the collection of clients // It is later included in the processing of all clients MasterClient(); // SNIP private: typedef std::set<Base *> Clients; Clients clients_; // Thread function that iterates over all clients // including this instance and makes calls on them void Process(); }; // file BaseClient.h class MasterClient; class BaseClient { public: // Constructor BaseClient(MasterClient * master); // SNIP interface private: MasterClient * master_; // I really need this to be a shared_ptr // Thread function that makes calls to the MasterClient virtual void Process(); }; ---------------------------- I gave it my best shot and have 2 errors that I can't figure out: C2664: BaseClient::BaseClient(boost::shared_ptr<T>) cannot convert parameter 1 from boost::shared_ptr<T> to boost::shared_ptr<T> C2385: ambiguous access of 'shared_from_this' I have to use enable shared from this to be passing around the shared_ptr from myself, no? I am also worried about using this in the intializer list, is it a problem? I believe both classes cannot inherit from it. I am not sure how to change it up. any suggestions? We are using VC2008, so I cannot use the standard shared_ptr yet, but I believe the boost version is the same... My attempt: /* * BaseClient.h */ #ifndef BASECLIENT_H #define BASECLIENT_H #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> //------------------------------- class MasterClient; //------------------------------- class BaseClient : public boost::enable_shared_from_this<BaseClient> { public: typedef boost::shared_ptr<BaseClient> SharedPtr; // Enforces that every instance must be a shared_ptr for shared_from_this requirement static BaseClient::SharedPtr Create(boost::shared_ptr<MasterClient> master); protected: BaseClient(boost::shared_ptr<MasterClient> master); virtual ~BaseClient(); boost::shared_ptr<MasterClient> master_; }; #endif /* * BaseClient.cpp */ #include "BaseClient.h" #include "MasterClient.h" //------------------------------- BaseClient::SharedPtr BaseClient::Create(boost::shared_ptr<MasterClient> master) { return BaseClient::SharedPtr(new BaseClient(master)); } //------------------------------- BaseClient::BaseClient(boost::shared_ptr<MasterClient> master) : master_(master) { master->InsertClient(shared_from_this()); } //------------------------------- BaseClient::~BaseClient() { } /* * MasterClient.h */ #ifndef MASTERCLIENT_H #define MASTERCLIENT_H #include "BaseClient.h" #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> #include <set> //------------------------------- class MasterClient : public BaseClient , public boost::enable_shared_from_this<MasterClient> { public: typedef boost::shared_ptr<MasterClient> SharedPtr; // Enforces that every instance must be a shared_ptr for shared_from_this requirement static MasterClient::SharedPtr Create(); protected: typedef std::set<BaseClient::SharedPtr> Clients; Clients clients_; MasterClient(); ~MasterClient(); }; #endif /* * MasterClient.cpp */ #include "MasterClient.h" //------------------------------- MasterClient::SharedPtr MasterClient::Create() { return MasterClient::SharedPtr(new MasterClient()); } //------------------------------- MasterClient::MasterClient() : BaseClient(MasterClient::shared_from_this()) { } //------------------------------- MasterClient::~MasterClient() { }

On Fri, Mar 30, 2012 at 12:26 PM, Christopher Pisz <cpisz@austin.rr.com> wrote:
What are one's options when the code one is working on contains a circular dependency and one is trying to update it to use a shared_ptr vs a raw pointer?
You could use weak_ptr to break shared_ptr cycles. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

Emil Dotchevski <emildotchevski <at> gmail.com> writes:
On Fri, Mar 30, 2012 at 12:26 PM, Christopher Pisz <cpisz <at>
What are one's options when the code one is working on contains a circular dependency and one is trying to update it to use a shared_ptr vs a raw
austin.rr.com> wrote: pointer?
You could use weak_ptr to break shared_ptr cycles.
Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode
From boost docs: Q. Can an object create a weak_ptr to itself in its constructor?
A. No. A weak_ptr can only be created from a shared_ptr, and at object construction time no shared_ptr to the object exists yet. This is the problem I cannot seem to easily overcome in both the case of the shared and weak ptr. It seems to work with a raw this pointer, but then I cannot achieve my goal.

On Fri, Mar 30, 2012 at 08:14:18PM +0000, Christopher Pisz wrote:
Emil Dotchevski <emildotchevski <at> gmail.com> writes:
You could use weak_ptr to break shared_ptr cycles.
Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode
From boost docs: Q. Can an object create a weak_ptr to itself in its constructor?
A. No. A weak_ptr can only be created from a shared_ptr, and at object construction time no shared_ptr to the object exists yet.
This is the problem I cannot seem to easily overcome in both the case of the shared and weak ptr. It seems to work with a raw this pointer, but then I cannot achieve my goal.
If you have control over the places where the objects of the type are created, you might want to have two-phase initialization with a factory function to protect you from misuse. That is, something like (ignoring access and all): struct B { void init(weak_ptr<B> p) { self = p; } weak_ptr<B> self; }; struct D : B { }; shared_ptr<D> MakeD(..) { shared_ptr<D> ret = make_shared<D>(..); ret->init(ret); return ret; } -- Lars Viklund | zao@acc.umu.se
participants (3)
-
Christopher Pisz
-
Emil Dotchevski
-
Lars Viklund