Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to initialize a shared_ptr that is a member of a class?

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); } 
like image 736
Igor Avatar asked Aug 23 '10 07:08

Igor


People also ask

What does shared_ptr get () do?

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.

Can shared_ptr be Nullptr?

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 .

How is shared_ptr implemented C++?

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.

Can you copy shared_ptr?

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.


1 Answers

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.

like image 184
ereOn Avatar answered Sep 20 '22 15:09

ereOn