導入
1つの資源を「複数の場所で共有して持ちたい」ことがあります。そのためのスマートポインタが std::shared_ptr です。仕組み(参照カウント)と、その落とし穴を避ける weak_ptr まで押さえて、この章を締めます。
説明
shared_ptr は「何人が所有しているか」を数える参照カウントを持ちます。コピーするとカウントが増え、寿命が尽きると減り、0 になった瞬間に自動で解放されます。make_shared<型>(引数) で作ります。
flowchart TB r["資源(Dog)"] a["shared_ptr a"] --> r b["shared_ptr b(a をコピー)"] --> r note["参照カウント = 2<br/>両方が消えて 0 になったら解放"]
#include <iostream>
#include <memory>
using namespace std;
int main() {
shared_ptr<int> a = make_shared<int>(42);
cout << a.use_count() << endl; // 1(所有者は1人)
{
shared_ptr<int> b = a; // 共有(コピーOK)
cout << a.use_count() << endl; // 2
cout << *b << endl; // 42
} // ここで b が消え、カウントが 1 に戻る
cout << a.use_count() << endl; // 1
return 0; // a が消えてカウント 0 → ここで解放
}
注意点が「循環参照」です。2つのオブジェクトが shared_ptr で互いを持ち合うと、カウントが永遠に 0 にならず解放されません。片方を 所有しない参照 weak_ptr にすると断ち切れます。
#include <memory>
using namespace std;
struct Node {
shared_ptr<Node> next; // 次を所有
weak_ptr<Node> prev; // 前は所有しない(weak)→ 循環を防ぐ
};
flowchart TB a["shared_ptr で相互所有<br/>→ カウントが 0 にならず漏れる"] b["片方を weak_ptr に<br/>→ 循環が切れて正しく解放"] a -->|"循環を断つ"| b
まとめ
shared_ptr は参照カウントで所有を共有し、カウントが 0 で自動解放します。共有が本当に必要なときだけ使い、既定は unique_ptr を選びます。相互に持ち合う「循環参照」は weak_ptr(所有しない参照)で断ち切ります。これで生の new/delete を書かずに、安全なメモリ管理ができます。