I am not sure about a good way to initialize a shared_ptr
that is a member of a class. Can you tell me, whether the way that I choose in C::foo()
is fine, or is there a better solution?
class A { public: A(); }; class B { public: B(A* pa); }; class C { boost::shared_ptr<A> mA; boost::shared_ptr<B> mB; void foo(); }; void C::foo() { A* pa = new A; mA = boost::shared_ptr<A>(pa); B* pB = new B(pa); mB = boost::shared_ptr<B>(pb); }
A shared_ptr may share ownership of an object while storing a pointer to another object. get() returns the stored pointer, not the managed pointer.
A null shared_ptr does serve the same purpose as a raw null pointer. It might indicate the non-availability of data. However, for the most part, there is no reason for a null shared_ptr to possess a control block or a managed nullptr .
A cyclic shared_ptr chain can be broken by changing the code so that one of the references is a weak_ptr . This is done by assigning values between shared pointers and weak pointers, but a weak pointer doesn't affect the reference count. If the only pointers that point to an object are weak, the object is destroyed.
After you initialize a shared_ptr you can copy it, pass it by value in function arguments, and assign it to other shared_ptr instances.
Your code is quite correct (it works), but you can use the initialization list, like this:
C::C() : mA(new A), mB(new B(mA.get()) { }
Which is even more correct and as safe.
If, for whatever reason, new A
or new B
throws, you'll have no leak.
If new A
throws, then no memory is allocated, and the exception aborts your constructor as well. Nothing was constructed.
If new B
throws, and the exception will still abort your constructor: mA
will be destructed properly.
Of course, since an instance of B
requires a pointer to an instance of A
, the declaration order of the members matters.
The member declaration order is correct in your example, but if it was reversed, then your compiler would probably complain about mB
beeing initialized before mA
and the instantiation of mB
would likely fail (since mA
would not be constructed yet, thus calling mA.get()
invokes undefined behavior).
I would also suggest that you use a shared_ptr<A>
instead of a A*
as a parameter for your B
constructor (if it makes senses and if you can accept the little overhead). It would probably be safer.
Perhaps it is guaranteed that an instance of B
cannot live without an instance of A
and then my advice doesn't apply, but we're lacking of context here to give a definitive advice regarding this.
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