C++11標準ライブラリで追加されたenable_shared_from_this
クラステンプレートについてメモ。Boost.Smart Pointersライブラリでも同機能を提供している。
N3337 20.7.2.4/p1より引用。
A class T can inherit from
enable_shared_from_this<T>
to inherit theshared_from_this
member functions that obtain a shared_ptr instance pointing to*this
.
具体的な利用例としては http://www.boost.org/doc/html/boost_asio/tutorial/tutdaytime3.html など(使用理由の説明)。
正しい利用方法
「クラス型T
の*this
へのshared_ptr<T>
を取得」を実装するためのヘルパであり、対象クラスに対し CRTP(Curiously Recurring Template Pattern) の形で利用する。またenable_shared_from_this
はpublic継承とする必要がある*1。
#include <memory> struct X : public std::enable_shared_from_this<X> { void func() { // 自分自身(*this)へのshared_ptr<X>型を取り出し auto self = shared_from_this(); //... } }; auto ptr = std::make_shared<X>(/*...*/); /*...*/ = ptr->func();
この例では、X::func()
で取り出したshared_ptr
を同メンバ関数の外で引き続き保持することを仮定している。(X::func
メンバ関数内でしかthis
を使わないのであれば、そもそもshared_ptr
として取り出す必然性が無い。)
誤った利用方法(1)
本クラステンプレートの利用にあたっては、オブジェクト自身(*this
)がshared_ptr
で所有権管理されていることが前提となる。
struct X : public std::enable_shared_from_this<X> { void func() { auto self = shared_from_this(); // (2) NG: Requiresを満たさない } }; auto ptr = new X(/*...*/); // (1) shared_ptr管理でない場合... ptr->func();
上記コードのようにshared_from_this
メンバ関数の要件を満たさない場合の挙動は、C++規格では明確に定義されていない。なお、gcc 4.6.3ではstd::bad_weak_ptr
例外が送出された。(後述の内部実装がされていれば、他処理系でも同例外が送出される可能性あり。)
誤った利用方法(2)
struct Y { void func() { auto self = std:shared_ptr<Y>(this); // NG!! } }; auto ptr = std::make_shared<Y>(/*...*/); ptr->func();
上記コードのようにthis
から直接shared_ptr
を作成した場合、self
とptr
で連携がとれず所有権管理が正常に機能しない。(この例では変数self
のデストラクタで意図しないY::~Y()
が呼びだされる。)
// 前述コードの問題点を単純化したコード Y *obj = new Y; std::shared_ptr<Y> ptr(obj); std::shared_ptr<Y> self(obj); // NG!!
内部実装の例
enable_shared_from_this
クラステンプレートが提供する機能は「*this
へのweak_ptr
を保持(A)しておき、shared_from_this
メンバ関数でshared_ptr
へ変換(昇格)する」だけ。またshared_ptr
コンストラクタでは、“enable_shared_from_this
から派生したクラスであること” を検出して前述(A)*this
へのweak_ptr
を適切に設定する。実装例をN3337 20.7.2.4/p10-11より引用*2。
10 [ Note: A possible implementation is shown below:
template<class T> class enable_shared_from_this { private: weak_ptr<T> __weak_this; protected: constexpr enable_shared_from_this() : __weak_this() { } enable_shared_from_this(enable_shared_from_this const &) { } enable_shared_from_this& operator=(enable_shared_from_this const &) { return *this; } ~enable_shared_from_this() { } public: shared_ptr<T> shared_from_this() { return shared_ptr<T>(__weak_this); } shared_ptr<T const> shared_from_this() const { return shared_ptr<T const>(__weak_this); } };11 The
shared_ptr
constructors that create unique pointers can detect the presence of anenable_shared_from_this
base and assign the newly createdshared_ptr
to its__weak_this
member. -- end note ]
関連URL
*1:N3337 20.7.2.4/p7 "Requires: enable_shared_from_this
*2:boost::enable_shared_from_this の実装:http://www.boost.org/boost/smart_ptr/enable_shared_from_this.hpp