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
を実行する方が速いですか?
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
を使用しないでください。違いは、 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 を読む必要があります