2012-07-05 9 views
13

ブーストのmake_shared()関数は、shared_ptrを作成しようとする際に例外から安全であることが保証されています。なぜboostにmake_scoped()がないのですか?

make_scoped()はなぜ同じですか?共通のベストプラクティスはありますか?ここで

は私には安全ではないと思われるboost::scoped_ptr documentationからのコードの例です:

boost::scoped_ptr<Shoe> x(new Shoe); 

このコード行は順番にこれら三つを行います。

  • Shoeのヒープ・メモリを割り当て
  • のコンストラクタを呼び出すShoe
  • Shoeのコンストラクタが例外をスローした場合、 メモリがリークされます boost::scoped_ptr<Shoe>

のコンストラクタを呼び出します。 (R. Martinho Fernandesの回答を参照)scoped_ptrはまだ構築されていないため、割り当て解除を処理しません。

これは見落としですか?それとも、私が気付かなかった解決策がありますか?

+0

この例は安全ですが、 'f(boost :: scoped_ptr (new Shoe)、g());'ではありません。問題を解決するためのコーディング慣行:常にスマートポインタの名前を変数またはメンバに指定し、仮のサブ式としてスマートポインタを構成しないでください。 – aschepler

答えて

13

コンストラクタが失敗した場合、メモリはリークされません。それはnewのセマンティクスの一部だ、関与なしスマートポインタ:make_sharedによって提供さ

struct Foo { Foo() { throw 23; } }; 
new Foo(); // no memory leaked 

追加例外の安全性は、あなたが2 shared_ptr式のsおよびを初期化しているときに、2つの初期化がの配列を決定していないから来ています関数呼び出しの引数の場合のように:

struct Bar { 
    Bar(bool fail) { 
     if(fail) throw 17; 
    } 
} 
f(shared_ptr<Bar>(new Bar(true)), shared_ptr<Bar>(new Bar(false))); 

new Bar(true)shared_ptr<Bar>(new Bar(true))new Bar(false)との評価の間にはシーケンシングがないので、では、次のようなことが起こる可能性があります。

  1. 評価され、成功しました。
  2. new Bar(true)評価され、失敗します。この評価の結果としてメモリがリークすることはありません。

いいえshared_ptrこの時点では、No#1で割り当てられたメモリがリークされるようになりました。

+0

私はあなたを理解しているように聞こえますか? 'new'はコンストラクタからスローされた例外を捕まえることを約束し、メモリを解放してから再投げますか? –

+3

@Drew:はい、その効果があります。興味があれば、これは§5.3.4paragrah 18の標準で説明されています。 –

+3

完全性のため、 'make_shared'の別の目的は(ほとんどの実装では)参照カウントのメモリをオブジェクトが作成され(オブジェクトとカウントに十分な大きさのブロックを割り当てます)、2つのヒープ割り当てがあってもパフォーマンスの低下を招くことはありません。 'scoped_ptr'(またはC++ 11の' unique_ptr')は参照カウントを必要としないので、その部門では何も得られません。 – John5342

1

シューズがスローされた場合、シューズは構築されないので、scoped_ptrは実際に行うことができません。いいえ? scoped_ptr xはスタック上にあり、スコープ出口でクリーンアップされます。

14

scoped_ptr predatesは移動セマンティクスであり、設計上はコピーできません。したがって、make_scopedは、関数からオブジェクトを返すために、その型は移動可能でもコピー可能でもなければならないため、実装することは不可能です。

関連する問題