2013-08-28 13 views
10

私はthis answerを読んでいたと著者は述べていboost best practicesを参照:C++でshared_ptrをC++ 11(std :: shared_ptr)に割り当てる:shared_ptrを一時変数に初期化するのはまだ悪いですか?

避け無名のshared_ptrを入力して保存するために一時使用します。 が、これは危険である理由は、この例を考えてみます。

void f(shared_ptr<int>, int); 
int g(); 

void ok() { 
    shared_ptr<int> p(new int(2)); 
    f(p, g()); 
} 

void bad() { 
    f(shared_ptr<int>(new int(2)), g()); 
} 

悪いが、メモリリークの可能性を認め、所定の位置に一時的 のshared_ptrを構築する一方で、機能OK]をクリックして、手紙にガイドラインを以下の。 関数の引数は不特定の順序で評価されるので、新しいint(2)を最初に評価する場合は 、g()の場合は可能で、例外がスローされた場合は をshared_ptrコンストラクタに渡すことはできません。 <...>

上記の例外安全性の問題も ブースト/ make_shared.hppで定義さmake_shared又はallocate_sharedファクトリ関数を用い によって除去することができます。これらのファクトリ関数は、割り当てを統合することによって の効率的なメリットも提供します。

私はアドバイスのこのビットはまだC++ 11 shared_ptrに適用される場合、私はmake_sharedを使用して起動しますが、私は思っていたと思います。 g()を投げてコールされるのを防ぐことができない理由を完全に理解していないため、私は尋ねます。

答えて

9

はい、C++ 11のshared_ptrは同じように動作します。

私は本当になぜ投げg()がコールされないようにするのか理解していないので、質問します。

ご理解いただけませんか?それは操作の問題の順序であり、標準ではには特定の順序のが必要ではありません。ステートメントを一連の式に解凍してみましょう:

auto __temp = new int(2); 
auto &&__temp2 = g(); 
auto __temp3 = shared_ptr<int>(__temp); 

今問題がありますか? gがスローした場合、__temp3は決して初期化されません。したがって、__tempがリークになります。

C++標準では、ステートメントをこのようにアンパックする必要はありません。しかし、はそれを禁止していませんです。コンパイラは、これらの独立した式を順番どおりに並べ替えることができますが、適合性はあります。

+0

私はより良い説明を求めることができませんでしたが、このようなものの「アンパックオーダー」は必ずしも同じではないと私は思っています。また、私はまだrvalue参照の適切な理解を得るチャンスを持っていない。 –

+0

@StevenLu:値の参照はそれとは関係ありません。 'auto &&'を使って' g() 'の結果を捕捉し、関数を呼び出すときに正しく転送できるようにしました。それは操作の順序とは関係がありません。また、順序はおそらく同じであろう... *コンパイラ全体ではない。 –

+0

ああ。参照してください、私はそれが "私がまだ理解していないこと"であることを知っていたので、私はさらに調査しませんでした。しかし、この(擬似)コードは、コンパイラがintを割り振った後に 'g()' **を構築するコードをどのように生成する可能性があり、最初の2つの行が反対の注文(その場合、物事はうまくいくでしょう)。 –

4

C++ 11では評価の順番について何も変わっていないと思います。つまり、安全性に関しては、std::make_shared<T>(...)を使用する方が、2つではなく1つのメモリ割り振りだけで済むという利点があります。f()引数の次評価は完全に有効です:

  1. $tmp = new int(1)(提供コンパイラ、一時的な変数を示すために$tmpを使用して)
  2. g()
  3. std::shared_ptr<int>($tmp)
  4. 何の問題に関しては

今、g()がスローすると、すなわち、std::shared_ptr<int>は決して構築されず、$tmpは漏洩される。

関連する問題