【C++学習|豆知識】クラス内部から自分自身を安全に共有する:shared_from_this() の活用術

導入

C++でスマートポインタ(std::shared_ptr)を扱っている際、「クラスのメンバ関数の中で、自分自身を指すstd::shared_ptrが欲しい」と思ったことはありませんか?実は、単純にthisポインタから新しいstd::shared_ptrを作成しようとすると、二重解放によるクラッシュを引き起こす危険があります。これを安全に解決するのが std::enable_shared_from_this です。今回は、安全なオブジェクト共有を実現するこのテクニックを解説します。

基礎知識

通常、std::shared_ptrはオブジェクトの生存期間を管理するためのカウンタを持っています。もし、同じインスタンスに対して別々のstd::shared_ptrを(例えば、thisポインタから)作成してしまうと、それぞれの管理カウンタが独立してしまい、一方が解放されるともう一方は不正なメモリを指すことになります。
std::enable_shared_from_this を継承すると、クラス内部に既存の管理カウンタを参照するための仕組みが組み込まれます。これにより、すでに管理されているstd::shared_ptrと同期した新しいポインタを安全に取り出せるようになります。

実装/解決策

実装は非常にシンプルです。まず、対象となるクラスに std::enable_shared_from_this<クラス名> を継承させます。その後、内部で自分自身のポインタが必要なタイミングで shared_from_this() を呼び出すだけです。注意点として、このメソッドは「そのオブジェクトがすでにstd::shared_ptrによって管理されている状態」でなければ例外(std::bad_weak_ptr)を投げます。そのため、スタック上に作成されたインスタンスに対しては使用できない点に注意してください。

サンプルプログラム

以下のコードをコピーして、コンパイル・実行してみてください。

include
include

// std::enable_shared_from_thisを継承することで機能が有効になります
class MyClass : public std::enable_shared_from_this {
public:
void doSomething() {
// 自分自身を共有するstd::shared_ptrを取得
std::shared_ptr self = shared_from_this();
std::cout << "共有ポインタを取得しました。現在の参照数: " << self.use_count() << std::endl; } }; int main() { // 必ずstd::shared_ptr経由でオブジェクトを作成する必要があります auto obj = std::make_shared();

obj->doSomething();

return 0;
}

応用・注意点

現場でよくある失敗として、コンストラクタ内で shared_from_this() を呼び出してしまうケースがあります。コンストラクタ実行中、まだそのオブジェクトはstd::shared_ptrによって管理され始めていないため、例外が発生します。自分自身のポインタを別のクラスに渡す必要がある場合は、コンストラクタではなく、初期化用のメソッド(例えば Init() や Start())を作成し、そこで呼び出すのが定石です。また、循環参照を防ぐために、保持する側には std::weak_ptr を活用することも検討してください。

コメント

タイトルとURLをコピーしました