M.7 std::shared_ptr


https://www.learncpp.com/cpp-tutorial/stdshared_ptr/
Unique ptrは、std::unique ptrオブジェクトでリソースを管理するのとは異なります.
std::shared ptrは、複数のスマートポインタがリソースを共有できるように設計されています.
これは、複数のstd::shared ptrオブジェクトが同じリソースを指すことができることを意味します.内部では、std::shared ptrは、リソースを管理しているshared ptrの数を追跡し続けます.少なくとも1つのstd::shared ptrが管理されている限り、リソースは解放されません.リソースを解放するように設計されたのは、最後のshared ptrも役割ドメインを破壊または超えた場合に限られる.
std::shared ptrもヘッダで定義
#include <iostream>
#include <memory> // for std::shared_ptr

class Resource
{
public:
	Resource() { std::cout << "Resource acquired\n"; }
	~Resource() { std::cout << "Resource destroyed\n"; }
};

int main()
{
	// allocate a Resource object and have it owned by std::shared_ptr
	Resource *res = new Resource;
	std::shared_ptr<Resource> ptr1{ res };
	{
		std::shared_ptr<Resource> ptr2 { ptr1 }; // make another std::shared_ptr pointing to the same thing

		std::cout << "Killing one shared pointer\n";
	} // ptr2 goes out of scope here, but nothing happens

	std::cout << "Killing another shared pointer\n";

	return 0;
} // ptr1 goes out of scope here, and the allocated Resource is destroyed
前述したように、ptr 1とptr 2は同じオブジェクトを管理しますが、問題は発生しません.
最後のptr 1が破壊されるまで、リソースは解放されません.
従って、出力は以下のようになる
Resource acquired
Killing one shared pointer
Killing another shared pointer
Resource destroyed
しかし、上記のプログラムでは、resで直接ptr 2を作成するのではなく、ptr 1でinitializationでオブジェクトを作成することに注意してください.
これはとても重要です.
次の例を示します.
#include <iostream>
#include <memory> // for std::shared_ptr

class Resource
{
public:
	Resource() { std::cout << "Resource acquired\n"; }
	~Resource() { std::cout << "Resource destroyed\n"; }
};

int main()
{
	Resource *res = new Resource;
	std::shared_ptr<Resource> ptr1 { res };
	{
		std::shared_ptr<Resource> ptr2 { res }; // create ptr2 directly from res (instead of ptr1)

		std::cout << "Killing one shared pointer\n";
	} // ptr2 goes out of scope here, and the allocated Resource is destroyed

	std::cout << "Killing another shared pointer\n";

	return 0;
} // ptr1 goes out of scope here, and the allocated Resource is destroyed again
上のプログラムは以下の出力を与えます
Resource acquired
Killing one shared pointer
Resource destroyed
Killing another shared pointer
Resource destroyed
そして衝突した
違いはresを用いてptr 1とptr 2を直接作成することである.
結果は同じobjectを指すが,両者の間には互いの存在が分からない.
従って、ptr 2がscopeを離れると、リソースは解放される.
このときmain関数が終了しdeleteを再試行するとクラッシュします
幸いなことに、これは避けやすいです.
shared::ptrが必要な場合はcopyで生成できます

Best practice


Always make a copy of an existing std::shared_ptr if you need more than one std::shared_ptr pointing to the same resource.
覚えてろ!

std::make_shared


std::make unique()と同様に、std::makeを共有することもできます.
#include <iostream>
#include <memory> // for std::shared_ptr

class Resource
{
public:
	Resource() { std::cout << "Resource acquired\n"; }
	~Resource() { std::cout << "Resource destroyed\n"; }
};

int main()
{
	// allocate a Resource object and have it owned by std::shared_ptr
	auto ptr1 { std::make_shared<Resource>() };
	{
		auto ptr2 { ptr1 }; // create ptr2 using copy of ptr1

		std::cout << "Killing one shared pointer\n";
	} // ptr2 goes out of scope here, but nothing happens

	std::cout << "Killing another shared pointer\n";

	return 0;
} // ptr1 goes out of scope here, and the allocated Resource is destroyed
make sharedを使用する理由はmake uniqueを使用する理由と同じです
もっと簡単で安全だから
上記の方法でオブジェクトを割り当てる利点は、同じオブジェクトを管理できないことです.

Digging into std::shared_ptr


std::unique ptrは内部で1つのポインタしか使用していないのとは異なります
std::shared ptrの場合、内部には2つのポインタが使用されます.
1つのポインタは、管理中のリソースを指します.
もう一つはコントロールブロックを指す
コントロールブロックは動的に割り当てられたオブジェクトです.
リソースを指すstd::shared ptrの数を含む多くのプロジェクトを追跡
shared::ptrを作成すると、上の2つのメモリがそれぞれ割り当てられます.
make sharedを使用する場合は、単一メモリ割り当てに最適化できます.
パフォーマンスの向上
上のように、controlblockの存在で
同じリソースに初期化されたshared ptrはcopyによって作成されません.
それぞれの制御ブロックがあります.だから墜落の原因だ
ただし、copyタスクとして作成すると、control blockが正しく更新される可能性があります.
予想されるshared ptr機能を使用できます

Shared pointers can be created from unique pointers


Unique pointerではmoveでshared ptrを生成できます
しかし、反対の状況を安全に実現することはできない.

std::shared ptr


unique ptrのように動的に割り当てて使用すると
objectがscopeから離れて破壊されないため、スマートポインタの機能は意味がありません
しかしunique ptrはスマートポインタを1つ心配するだけです
shared ptrの場合、複数のptrに注意する必要があります

Conclusion


std::shared ptrは、複数のスマートポインタ上で同じリソースを管理するために使用されます.
resourceは最後のshared ptrが破壊された瞬間に解放された