導入
C++におけるメモリ管理は、かつて `new` と `delete` を直接扱う必要があり、メモリリークや二重解放(Double Free)が頻発する難所でした。モダンC++においてその解決策となるのが「スマートポインタ」です。中でも std::shared_ptr は、複数のポインタで同一リソースの所有権を共有できる非常に強力なツールです。本記事では、実務で安全かつ効率的に扱うためのポイントを解説します。
基礎知識
std::shared_ptr は「参照カウンタ」という仕組みを利用しています。内部的に「このリソースを今何個のポインタが指しているか」を記録しており、新しい shared_ptr が作成されるとカウントが増え、破棄されると減ります。そして、カウンタがゼロになった瞬間に自動的にメモリが解放されます。これにより、プログラマが手動で `delete` を呼び出す必要がなくなり、例外が発生しても確実にメモリがクリーンアップされるようになります。
実装/解決策
実務で最も推奨されるのは、std::make_shared を使用することです。これにより、メモリの確保とオブジェクトの構築を一度に行えるため、パフォーマンスが向上し、例外安全性も高まります。また、生のポインタから直接 shared_ptr を生成するよりも、コードの記述量が減り、可読性も向上します。
サンプルプログラム
以下のコードは、std::shared_ptr の基本的な生成と共有、そしてスコープによる自動解放の挙動を示す実用的な例です。
#include
include
include
class Resource {
public:
Resource() { std::cout << "リソースの確保" << std::endl; }
~Resource() { std::cout << "リソースの解放" << std::endl; }
void sayHello() { std::cout << "こんにちは!" << std::endl; }
};
int main() {
// 1. std::make_shared でスマートポインタを作成
// メモリ確保が効率的に行われるため、推奨される書き方です
std::shared_ptr
{
// 2. 別の shared_ptr にコピー(所有権の共有)
// 参照カウンタが 2 になります
std::shared_ptr
ptr2->sayHello();
std::cout << "共有数: " << ptr1.use_count() << std::endl;
} // ptr2 がスコープを抜ける。参照カウンタが 1 に戻る
std::cout << "スコープを抜けました" << std::endl;
// main が終了すると ptr1 も破棄され、参照カウンタが 0 となり自動的にメモリが解放されます
return 0;
}
応用・注意点
実務で std::shared_ptr を使用する際、特に注意すべきは「循環参照」です。例えば、オブジェクトAがBを指し、BがAを指すような構造を作ると、互いに参照カウンタを減らさず、メモリリークが発生します。これを防ぐには、子側の参照に std::weak_ptr を活用してください。
また、std::shared_ptr は参照カウンタの更新というオーバーヘッドがあるため、単一の所有者しか存在しない場合は std::unique_ptr を優先的に検討するのも重要な設計判断です。パフォーマンスと安全性のバランスを意識して使い分けましょう。

コメント