6

この投稿と@kerek SB州による回答の1つに出くわしました

std::shared_ptr<Object> p1 = std::make_shared<Object>("foo");
std::shared_ptr<Object> p2(new Object("foo"));

コードでは、2 番目の変数はネイキッド ポインターであり、共有ポインターではありません。

今、肉に。make_shared は (実際には) より効率的です。これは、参照制御ブロックを実際のオブジェクトと共に 1 つの動的割り当てで割り当てるためです。対照的に、ネイキッド オブジェクト ポインターを受け取る shared_ptr のコンストラクターは、参照カウント用に別の動的変数を割り当てる必要があります。トレードオフは、割り当てがアロケータによって実行されるため、make_shared (またはその従兄弟の allocate_shared) ではカスタムのデリータを指定できないことです。

(これは、オブジェクト自体の構成には影響しません。オブジェクトの観点からは、2 つのバージョンに違いはありません。より効率的なのは、管理対象オブジェクトではなく、共有ポインター自体です。)

この投稿に関して2つの質問があります。誰かがこれを明確にしてくれれば幸いです

  1. 2 番目のポインタが共有ポインタではないのはなぜですか? それは参照カウントをインクリメントしませんか

  2. make_shared は 1 つのメモリ割り当てのみを作成し、new は 2 つを作成して make_shared をより効率的にするにはどうすればよいですか?

これについて少し説明していただければ幸いです。

4

4 に答える 4

3
  1. 2 番目の変数と呼ばれるコードは、実際には次のとおりです (OP のコードから取得)。

    auto ptr_res2(new Object("new"));
    

    これはを作成するのではなくstd::shared_ptr、 へのポインタを作成しますObject

  2. ネイキッド ポインターを受け取るコンストラクターを使用して を作成する場合、std::shared_ptr既に割り当てられているメモリ (たとえば、割り当てられた using ) へのポインターを渡す必要がありますnewstd::shared_ptrこれは、オブジェクト自体の作成時に、オブジェクトのメモリがすでに割り当てられていることを意味します。std::shared_ptr参照カウンターなど、独自の動作のためにメモリを割り当てる必要があります。そのため、2 つの割り当てがあります。1 つnewは ctor に渡されたものを使用し、もう 1 つはそれ自体std::shared_ptrを構築するときに必要です。std::shared_ptr

    Object* ptr = new Object{"Foo"}; // Allocation 1 (object).
    std::shared_ptr<Object> p1{ptr}; // Allocation 2 (internal counters).
    

    ヘルパー関数は、オブジェクト自体へのポインターではなく、オブジェクトの構築に必要な引数std::make_sharedを渡すときに、1 つの割り当てのみを使用します。その後、オブジェクトと参照カウンターの両方を保持するメモリを一度割り当てることができます。std::make_shared

    auto p2 = std::make_shared<Object>{"Foo"} // Allocation 1 (object & counter).
    
于 2014-11-22T21:56:27.707 に答える
2

2 番目のポインタが共有ポインタではないのはなぜですか? それは参照カウントをインクリメントしませんか

引用は、スマートポインターを作成すると主張しているが、実際にはそうしていない元のポスターのコードを参照していると思います。ptr_res2は単なる通常のポインターです。

cout << "Create smart_ptr using new..." << endl;
auto ptr_res2(new Object("new"));
cout << "Create smart_ptr using new: done." << endl;

make_shared はどのようにして 1 つのメモリ割り当てのみを作成し、new は 2 つを作成して make_shared をより効率的にしますか?

make_sharedカウンターとオブジェクト自体にスロットを割り当てる必要があります。一度にメモリを割り当てて、その一部をカウンターに使用し、残りをオブジェクトに使用することができます。

これは、カウンターとオブジェクト自体がメモリ内で互いに隣接しているため、データの局所性が向上することも意味することに注意してください。

于 2014-11-22T21:46:16.457 に答える
1
  1. 2 つ目はまだ共有ポインタです。shared_ptr のコンストラクターを呼び出しています。

http://www.cplusplus.com/reference/memory/shared_ptr/shared_ptr/

  1. ただし、make_shared を使用すると、2 つの割り当てではなく 1 つの割り当てしか行われないため、より効率的です。shared_ptr には、Object 用のヒープ上にスペースが必要であり、マネージャーも共有ポインターとウィーク ポインターの数を追跡する必要があることに注意してください。コンストラクターを使用している場合は、オブジェクトにスペースを割り当ててから、マネージャーにスペースを割り当てる必要があるコンストラクターにポインターを渡します。代わりに、make_shared を使用すると、オブジェクトとマネージャーを格納するメモリのチャンクが 1 つ割り当てられます。割り当ては比較的コストがかかるため、2 つよりも 1 つの方が適しています。
于 2014-11-22T21:46:49.817 に答える