10

私はこの回答を読んでいましたが、著者はブーストのベストプラクティスを参照しています。

入力を節約するために、名前のない 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());
}

関数 ok は文字どおりガイドラインに従いますが、bad は一時的な shared_ptr を所定の場所に構築し、メモリ リークの可能性を認めます。関数の引数は指定されていない順序で評価されるため、new int(2) が最初に評価され、g() が 2 番目に評価される可能性があり、g が例外をスローした場合、shared_ptr コンストラクターに到達しない可能性があります。<...>

上記の例外の安全性の問題は、boost/make_shared.hpp で定義されている make_shared または allocate_shared ファクトリ関数を使用することによっても解消される場合があります。これらのファクトリ関数は、割り当てを統合することによって効率の利点も提供します。

を使い始めるとmake_shared思いますが、このちょっとしたアドバイスが C++11 にも当てはまるかどうか疑問に思っていましたshared_ptrg()スローするとctorが呼び出されなくなる理由がよくわからないので、質問します。

4

2 に答える 2

9

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

g() をスローすると ctor が呼び出されなくなる理由がよくわからないので、質問します。

何を理解していないのですか?これは操作の順序の問題であり、標準では特定の順序は必要ありません。ステートメントを一連の式に展開しましょう。

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

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

C++ 標準では、ステートメントをこのようにアンパックする必要はありません。しかし、それを禁じているわけでもありません。コンパイラには、これらの独立した式を自由に順序付けることができますが、適切と思われます。

于 2013-08-28T02:19:24.307 に答える
4

C++11 での評価の順序に関しては何も変わっていないと思います。つまり、std::make_shared<T>(...)メモリ割り当てを 2 つではなく 1 つだけ要求するだけでなく、安全性に関しては、使用する方が適切なオプションです。

何の問題に関して: 次のf()議論の評価は完全に有効です:

  1. $tmp = new int(1)($tmpコンパイラが提供する一時変数を示すために使用)
  2. g()
  3. std::shared_ptr<int>($tmp)

これで、throws の場合g()、他の部分の評価は実行されません。つまり、std::shared_ptr<int>は構築されず、$tmpリークされます。

于 2013-08-28T02:22:00.237 に答える