std :: make_uniqueとstd :: unique_ptrのnewとの違い


130

std::make_uniqueような効率上の利点はありstd::make_sharedますか?

手動で構築するのと比較してstd::unique_ptr

std::make_unique<int>(1);         // vs
std::unique_ptr<int>(new int(1));

ないmake_shared任意の効率だけ長い手のコードを書く以上を持っていますか?
Ed Heal 2014年

9
@EdHeal make_sharedオブジェクトのスペースと制御ブロックのスペースの両方を1つの割り当てで一緒に割り当てることができるためです。その代償として、オブジェクトを制御ブロックとは別に解放することができないためweak_ptr、大量に使用すると、より多くのメモリを使用することになります。
bames53 2014年

おそらくこれは良い出発地点であるstackoverflow.com/questions/9302296/...は
Edはヒール

回答:


140

背後にmake_uniqueある動機は主に2つあります。

  • make_unique一時ファイルを作成する場合は安全ですが、明示的に使用するnew場合は、名前のない一時ファイルを使用しないという規則を覚えておく必要があります。

    foo(make_unique<T>(), make_unique<U>()); // exception safe
    
    foo(unique_ptr<T>(new T()), unique_ptr<U>(new U())); // unsafe*
  • make_unique最終的にの追加はnew、以前のルールではなく、「決して」使用しないように人々に指示できることを意味newしますunique_ptr

3番目の理由もあります。

  • make_unique冗長な型の使用は必要ありません。unique_ptr<T>(new T())->make_unique<T>()

使用方法のように実行時の効率を向上させる理由はありmake_sharedません(2番目の割り当てを回避するため、ピーク時のメモリ使用量が増える可能性があります)。

* C ++ 17にはルールの変更が含まれることが予想されます。これは、これがもはや安全ではないことを意味します。C ++委員会のペーパーP0400R0およびP0145R3を参照してください。


言うことはもっと理にかなっていてstd::unique_ptrstd::shared_ptr人々に「絶対に使わない」と言うことができる理由newです。
ティモシーシールズ

2
@TimothyShieldsええ、そういうことです。これは、C ++ 11には、我々が持っているだけのことだmake_sharedとそうmake_unique以前に欠落していた最後のピースがあります。
bames53 2014年

1
名前のない一時ファイルを使用しない理由を簡単に説明したり、リンクしたりできる方法はありますか?
Dan Nissenbaum 2016

14
実際には、からstackoverflow.com/a/19472607/368896、私はそれは...その答えからは、次の関数呼び出しを考える持っているff(unique_ptr<T>(new T), function_that_can_throw());答えを引用する- :コンパイラは、(順番に)呼び出すことが許可されています:new Tfunction_that_can_throw()unique_ptr<T>(...)。もちろん、function_that_can_throw実際に投げるとリークする。make_uniqueこのケースを防ぎます。 だから、私の質問に答えます。
Dan Nissenbaum 2016

3
std :: unique_ptr <T>(new T())を使用しなければならなかった1つの理由は、Tのコンストラクターがプライベートだったからです。std :: make_uniqueの呼び出しがクラスTのパブリックファクトリメソッドであったとしても、std :: make_uniqueの基礎となるメソッドの1つがプライベートコンストラクターにアクセスできなかったため、コンパイルされませんでした。std :: make_uniqueの実装に依存したくなかったので、このメソッドをフレンドにしたくありませんでした。したがって、唯一の解決策は、クラスTのファクトリメソッドでnewを呼び出し、それをstd :: unique_ptr <T>でラップすることでした。
Patrick

14

std::make_unique そして std::make_shared二つの理由があります。

  1. そのため、テンプレートタイプの引数を明示的にリストする必要はありません。
  2. std::unique_ptrまたはstd::shared_ptrコンストラクタの使用に対する追加の例外安全性。(ここの注セクションを参照してください。)

それは実際にはランタイム効率についてではありません。制御ブロックとT一度に割り当てられることについては少しありますが、それはより多くのボーナスであり、これらの機能が存在する動機ではないと思います。


また、例外的な安全のために用意されています。
0x499602D2 14年

@ 0x499602D2そして、それは良い追加です。このページはそれについて話します。
ティモシーシールズ

将来の読者のために、C ++ 17は関数の引数のインターリーブを許可しないため、例外安全性の引数は保持されません。2つの並列std::make_sharedのメモリ割り当てにより、他のメモリ割り当てが発生する前に、少なくとも1つがスマートポインタにラップされるため、リークは発生しません。
MathBunny

7

現在のスコープ外でクラスのコンストラクターにアクセスできないことが、代わりに、std::unique_ptr(new A())またはstd::shared_ptr(new A())直接使用する必要がある理由です。std::make_*()A


0

関数呼び出しを検討する

void function(std::unique_ptr<A>(new A()), std::unique_ptr<B>(new B())) { ... }

newはA()成功したが、new B()は例外をスローしたとします。これをキャッチして、プログラムの通常の実行を再開します。残念ながら、C ++標準では、オブジェクトAを破棄してメモリを解放する必要はありません。メモリが静かにリークし、クリーンアップする方法がありません。AとBをラップstd::make_uniquesして、リークが発生しないことを確認します。

void function(std::make_unique<A>(), std::make_unique<B>()) { ... }

ここでのポイントは std::make_unique<A>std::make_unique<B>が一時オブジェクトであり、一時オブジェクトのクリーンアップがC ++標準で正しく指定されていることです。それらのデストラクタがトリガーされ、メモリが解放されます。したがって、可能であれば、常にstd::make_uniqueとを使用してオブジェクトを割り当てることをお勧めしますstd::make_shared

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.