web-dev-qa-db-ja.com

std :: shared_ptr初期化:make_shared <Foo>()vs shared_ptr <T>(new Foo)

違いは何ですか:

std::shared_ptr<int> p = std::shared_ptr<int>( new int );

そして

std::shared_ptr<int> p = std::make_shared< int >();

どちらを好むのか、なぜですか?

P. S.これはすでに回答されているはずですが、同様の質問は見つかりません。

39
Violet Giraffe

どちらの例も、必要以上に冗長です。

std::shared_ptr<int> p(new int);  // or '=shared_ptr<int>(new int)' if you insist
auto p = std::make_shared<int>(); // or 'std::shared_ptr<int> p' if you insist

違いは何ですか?

主な違いは、1つ目は2つのメモリ割り当てを必要とすることです。1つは管理対象オブジェクト(new int)用、もう1つは参照カウント用です。 make_sharedは、単一のメモリブロックを割り当て、その中に両方を作成する必要があります。

どちらを好むのか、なぜですか?

通常、make_sharedを使用する方が効率的です。別の回答に記載されているように、管理対象オブジェクトへの生のポインタが存在しないため、メモリリークの可能性も回避されます。

ただし、コメントに記載されているように、共有カウントの削除を妨げる弱いポインターが残っている場合、オブジェクトが破棄されてもメモリが解放されないという潜在的な欠点があります。

57
Mike Seymour

en.cppreference.com から

対照的に、宣言std::shared_ptr<T> p(new T(Args...))は少なくとも2つのメモリ割り当てを実行するため、不要なオーバーヘッドが発生する可能性があります。

また、f(shared_ptr<int>(new int(42)), g())は、gが例外をスローした場合にメモリリークを引き起こす可能性があります。 make_sharedが使用されている場合、この問題は存在しません。

だから、make_shared可能であればアプローチします。

14
Adri C.S.

make_sharedはデフォルトの割り当て/割り当て解除機能の使用に制限されているため、さらに制御したい場合、make_sharedはオプションではありません。言い換えれば、

std::shared_ptr<uint8_t>(p, [](uint8_t *p){ /*user code */}); 

make_sharedを使用することはできません。代わりにallocate_sharedを使用することもできますが、指定できるのはアロケーターのみで、削除機能は指定できません。ラップされたクラスの割り当てと削除を制御する必要がある場合があります。

9
doc_ds