enable_shared_from_thisから派生することで、クラスのメンバ関数内でshared_from_this関数により自身のshared_ptrを取得することができます。
大変便利なんですが、以下のような注意点があります。
- オブジェクトをshared_ptrで管理している必要がある
- コンストラクタ内でshared_from_this関数が使えない
初期化パターンのコード例
次のような初期化パターンにより、上記問題を解決することができます。
#include <memory>
class Foo : public std::enable_shared_from_this<Foo>
{
using SpFoo = std::shared_ptr<Foo>;
// 1.自由にコンストラクタを使用できないようにする
Foo(){}
void initialize()
{
// 2.初期化時にshared_from_this()を使いたいときはinitialize関数内で使用
auto sp = shared_from_this();
// 何かの処理
}
public:
// 3.利用者は必ずcreate関数経由でshared_ptr管理されたオブジェクトを使用
static SpFoo create()
{
struct OBJ : Foo{};
auto sp = std::make_shared<OBJ>();
// 4.create関数内で初期化処理を実施
sp->initialize();
return sp;
}
};
int main()
{
auto foo = Foo::create();
return 0;
}
初期化パターンのポイント
1.privateコンストラクタにする。
オブジェクトをshared_ptrで管理する必要があるため、コンストラクタをprivateにすることで自由にオブジェクトを生成できなくします。
2.初期化時にshared_from_this関数を使いたい場合はコンストラクタではなく、initialize関数に記載する。
コンストラクタではオブジェクトの生成が完了していないため、shared_from_this関数が動作しません。そのため、コンストラクタの後に実施する初期化関数でshared_from_thisが必要な初期化処理を記載します。
3.create関数でshared_ptrで管理されたオブジェクトを生成する。
create関数によりshared_ptrで管理されたオブジェクトを生成できるようにします。std::make_sharedでprivateコンストラクタを呼ぶにはちょっとしたテクニックが必要になります。
クラス内テンプレートクラスと継承を利用してmake_sharedでprivateコンストラクタを呼ぶ
4.create関数でオブジェクトを作ってからinitialize関数を実施する。
initialize関数の実施を利用者に任せてしまうと、初期化忘れが起きる可能性があります。そのため、create関数で得られたオブジェクトを返す前に初期化処理を実施します。