I have to register an object in a container upon its creation. Without smart pointers I'd use something like this:
a_class::a_class() { register_somewhere(this); } With smart pointers I should use shared_from_this but I can't use that in the constructor.
Is there a clean way to solve this problem? What would you do in a similar situation? I'm thinking about introducing an init method to call just after creation and put everything in a factory function like this:
boost::shared_ptr<a_class> create_a() { boost::shared_ptr<a_class> ptr(new a_class); ptr->init(); return ptr; } Is it fine or there is a standard procedure to follow in such cases?
EDIT: Actually my case is more complex. I have 2 object which shall maintain pointers each other. So the truth is I'm not "registering" but creating another object (let's say b_class) which requires this as a parameter. b_class receives this as a weak pointer and stores it.
I'm adding this because since you are giving me design advices (which are very appreciated) at least you can know what I'm doing:
a_class::a_class() { b = new b_class(this); } In my program a_class is an entity and b_class is one of the concrete classes representing the state (in the constructor it's just the starting state). a_class needs a pointer to the current state and b_class needs to manipulate the entity.
a_class is responsible for creating and destroying b_class instances and thus maintains a shared_ptr to them but b_class need to manipulate a_class and thus maintains a weak pointer. a_class instance "survives" b_class instances.
Do you suggest to avoid using smart pointers in this case?
By deriving your class from the class template enable_shared_from_this , you inherit a method shared_from_this that returns a shared_ptr instance to this . Note(2) you cannot call enable_shared_from_this inside the constructor.
shared_from_this. returns a shared_ptr which shares ownership of *this. (public member function)
a_classis responsible for creating and destroyingb_classinstances
...
a_classinstance "survives"b_classinstances.
Given these two facts, there should be no danger that a b_class instance can attempt to access an a_class instance after the a_class instance has been destroyed as the a_class instance is responsible for destroying the b_class instances.
b_class can just hold a pointer to it's associated a_class instance. A raw pointer doesn't express any ownership which is appropriate for this case.
In this example it doesn't matter how the a_class is created, dynamically, part of a aggregated object, etc. Whatever creates a_class manages its lifetime just as a_class manages the lifetime of the b_class which it instantiates.
E.g.
class a_class; class b_class { public: b_class( a_class* a_ ) : a( a_ ) {} private: a_class* a; }; class a_class { public: a_class() : b( new b_class(this) ) {} private: boost::shared_ptr<b_class> b; }; Note, in this toy example there is no need for a shared_ptr, an object member would work just as well (assuming that you don't copy your entity class).
class a_class { public: a_class() : b( this ) {} private: b_class b; };
If you absolutely need a shared_ptr during construction, it's best to have an 'init' function. In fact, this is the only decent approach I can think of. You should probably have a special function that creates objects of this type, to ensure init() is called, if you choose this path.
However, depending on what you're registering for, it may be a better idea to give whatever object you're registering with a plain pointer to the object in the constructor, rather than a shared_ptr. Then in the destructor, you can just unregister the object from the manager.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With