web-dev-qa-db-ja.com

クラスのメンバーであるshared_ptrを初期化する方法は?

クラスのメンバーである_shared_ptr_を初期化する良い方法についてはわかりません。 C::foo()で選択する方法が良いか、それとももっと良い解決策があるか教えていただけますか?

_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);
}
_
36
Igor Oks

あなたのコードはかなり正しいです(それは動作します)が、あなたはこのように初期化リストを使うことができます:

_C::C() :
  mA(new A),
  mB(new B(mA.get())
{
}
_

これはさらに正確で安全です。

何らかの理由で_new A_または_new B_がスローした場合、リークは発生しません。

_new A_がスローされた場合、メモリは割り当てられず、例外によってコンストラクタも中止されます。何も構築されていません。

_new B_がスローされ、例外によってコンストラクタが中止される場合:mAは適切に破棄されます。

もちろん、BのインスタンスにはAのインスタンスへのポインターが必要なので、メンバーの宣言順序mattersです。

メンバー宣言の順序はあなたの例では正しいですが、逆になっていると、コンパイラはおそらくmBの前に初期化されたmAの初期化について不満を抱き、mBのインスタンス化はおそらく失敗します(mAはまだ構築されていないため、mA.get()を呼び出すと、未定義の動作が呼び出されます)。


Bコンストラクターのパラメーターとして_shared_ptr<A>_の代わりに_A*_を使用することもお勧めします(if意味があり、受け入れることができるかどうか少しオーバーヘッド)。それはおそらくより安全でしょう。

おそらく、BのインスタンスはAのインスタンスなしでは生きられないことが保証されているため、私のアドバイスは当てはまりませんが、これに関する決定的なアドバイスを提供するためのコンテキストが不足しています。

30
ereOn