web-dev-qa-db-ja.com

new演算子よりもstd :: make_uniqueを使用する利点

std::make_uniqueを初期化するためにnew演算子よりもstd::unique_ptrを使用する利点は何ですか?

言い換えれば、なぜ

std::unique_ptr<SomeObject> a = std::make_unique(SomeObject(...))

するよりも良い

std::unique_ptr<SomeObject> a = new SomeObject(...)

私はオンラインでたくさん調べてみましたが、現代のC++で演算子newを避けるのは良い経験則であることは知っていますが、この正確なシナリオで利点が何であるかはわかりません。発生する可能性のあるメモリリークを防止できますかnewを使用するよりもstd::make_uniqueを実行する方が速いですか?

80
niting

長所

  • make_uniqueは、ユーザーに免責事項なしで「new/deleteおよびnew[]/delete[]を言わないでください」と教えます。

  • make_uniqueは、make_sharedと2つの利点を共有しています(3番目の利点である効率の向上を除く)。最初に、unique_ptr<LongTypeName> up(new LongTypeName(args))LongTypeNameを2回言及する必要がありますが、auto up = make_unique<LongTypeName>(args)は1回言及します。

  • make_uniqueは、foo(unique_ptr<X>(new X)unique_ptr<Y>(new Y))などの式によってトリガーされる不特定の評価順序のリークを防ぎます。 (「newと言ってはいけない」というアドバイスに従うと、すぐに名前付きunique_ptrに渡さない限り、「newと言ってはいけない」よりも簡単です。)

  • make_uniqueは例外の安全性のために慎重に実装されており、unique_ptrコンストラクターを直接呼び出すよりも推奨されます。

make_uniqueを使用しない場合

  • カスタム削除ツールが必要な場合、または他の場所から生のポインターを採用している場合は、make_uniqueを使用しないでください。

ソース

  1. std::make_uniqueの提案
  2. Herb SutterのGotW#89ソリューション:スマートポインター
82
101010

違いは、 std::make_unique はタイプ std::unique_ptr のオブジェクトを返し、newは作成されたオブジェクトへのポインターを返すことです。メモリ割り当てエラーの場合、両方ともスローされます。 しばらくお待ちください、それほど簡単ではありません。さらに読む

以下のような関数を考えてください:

void func(ClassA* a, ClassB* b){
     ......
}

func(new A(), new B())のような呼び出しを行うとき;コンパイラは、関数の引数を左から右へ、または希望する任意の順序で評価することを選択できます。左から右への評価を想定してみましょう:最初のnew式は成功したが、2番目のnew式がスローされた場合はどうなりますか?

ここでの本当の危険は、そのような例外をキャッチしたときです。はい、new B()によってスローされた例外をキャッチし、通常の実行を再開した可能性がありますが、new A()はすでに成功しており、そのメモリは静かにリークされます。誰もクリーンアップしません... *sobs...

しかし、make_uniqueを使用すると、スタックの巻き戻しが発生するため(そして、以前に作成されたオブジェクトのデストラクタが実行されるため)、リークすることはありません。したがって、make_uniqueを優先すると、 exception safety に制限されます。この場合、std::make_unique"Basic Exception Safety" を提供します。これは、newによって割り当てられたメモリと作成されたオブジェクトが何であっても孤立することはありません。時間の終わりまで... :-)

Herb Sutter GoTW102 を読む必要があります

37
WhiZTiM