5

make_shared は、オブジェクトと参照カウンターに 1 つのブロックを割り当てます。したがって、このような手法を使用すると明らかにパフォーマンスが向上します。

私はVS2012で簡単な実験を行い、「証拠」を探していました:

std::shared_ptr<Test> sp2 = std::make_shared<Test>();
std::shared_ptr<Test> sp(new Test());
// Test is a simple class with int 'm_value' member

デバッグ時にローカルビューでこのようなものを取得しました(一部の行は削除されています)

-   sp2 shared_ptr {m_value=0 }  [make_shared] std::shared_ptr<Test>
+   _Ptr    0x01208dec {m_value=0 } Test *
+   _Rep    0x01208de0 make_shared  std::_Ref_count_base *

-   sp  shared_ptr {m_value=0 } [default] std::shared_ptr<Test>
+   _Ptr    0x01203c50 {m_value=0 } Test *
+   _Rep    0x01208d90 default  std::_Ref_count_base *

sp2は 0x01208de0 に割り当てられ(参照カウンターがあります)、0x01208decTest オブジェクトがあるようです。場所は互いに非常に近いです。

2 番目のバージョンでは、参照カウンターに0x01208d90 、オブジェクトに0x01203c50があります。それらの場所はかなり離れています。

これは適切な出力ですか?これを正しく理解していますか?

4

3 に答える 3

7

の cppreference のページmake_sharedを読むと、次のように書かれています。

この関数は、単一のメモリ割り当てでTオブジェクトとの制御ブロックにメモリを割り当てます。shared_ptr対照的に、宣言std::shared_ptr<T> p(new T(Args...))では 2 つのメモリ割り当てが実行されるため、不要なオーバーヘッドが発生する可能性があります。

したがって、これは意図された動作であり、適切に解釈しました。

そしてもちろん、それは理にかなっています。shared_ptr既に割り当てたオブジェクトの割り当てをどのように制御できますか? を使用make_sharedすると、オブジェクトの割り当てを任せることができるため、カウンターのすぐ横など、必要な場所にオブジェクトを割り当てることができます。

補遺: Pete Becker がコメントで指摘したように、標準の §20.7.2.2.6/6 では、実装は 1 つの割り当てのみを実行することが推奨されていますが、必須ではないと述べています。したがって、あなたが観察したこの動作は信頼すべきではありませんが、常にmake_shared.

于 2013-02-02T20:06:55.217 に答える
3

はい、表示されている出力は正しいです。

sp2で作成された の場合make_shared<>()、参照カウンタと割り当てられたオブジェクトを含む連続したメモリのブロックが 1 つあります。これが、2 つのアドレスが近接している理由であり、存在する主な理由の 1 つでもあります (2 つではなく1 つの割り当てmake_shared<>()のみを実行するため)。

の場合はsp、代わりに、オブジェクトを個別に割り当ててから、オブジェクトnew Test()を構築しshared_ptrます。のコンストラクターはshared_ptr、参照カウンターの新しい割り当てを発行する必要があります。このため、指しているオブジェクトのアドレスと参照カウンタのアドレスは離れています。

于 2013-02-02T20:07:45.353 に答える
1

これは適切な出力ですか?

そのように見える。

全体的なポイントstd::make_sharedはパフォーマンスです。動的メモリ割り当ては比較的高価であり、参照カウンターを保持するためだけに余分な割り当てを行うと、かなり無駄になる可能性があります。したがって、オブジェクトとカウンターの両方std::make_sharedに十分な大きさのメモリのスラブを割り当ててから、そのスラブ内の正しい場所で(配置 newを使用して) オブジェクトを初期化します。

于 2013-02-02T20:12:42.687 に答える