std:: enable_shared_from_this
|
ヘッダーで定義
<memory>
|
||
|
template
<
class
T
>
class enable_shared_from_this ; |
(C++11以降) | |
std::enable_shared_from_this
は、
t
というオブジェクトが現在
std::shared_ptr
によって管理されている場合に、
pt1
、
pt2
などの追加の
std::shared_ptr
インスタンスを安全に生成することを可能にします。これらはすべて
pt
と
t
の所有権を共有します。
std::enable_shared_from_this<T>
から公開継承することで、型
T
はメンバ関数
shared_from_this
を利用できるようになります。型
T
のオブジェクト
t
が
std::
shared_ptr
<
T
>
である
pt
によって管理されている場合、
T::shared_from_this
を呼び出すと、
t
の所有権を
pt
と共有する新たな
std::
shared_ptr
<
T
>
が返されます。
目次 |
データメンバ
| メンバー | 説明 |
mutable
std::
weak_ptr
<
T
>
weak_this
|
このオブジェクトの最初の共有所有者の制御ブロックを追跡するオブジェクト
*
this
( 説明専用メンバーオブジェクト* ) |
メンバー関数
enable_shared_from_this
オブジェクトを構築する
(protected member function) |
|
enable_shared_from_this
オブジェクトを破棄する
(protected member function) |
|
|
*
this
への参照を返す
(protected member function) |
|
|
*
this
の所有権を共有する
std::shared_ptr
を返す
(public member function) |
|
|
(C++17)
|
*
this
の所有権を共有する
std::weak_ptr
を返す
(public member function) |
注記
std::shared_ptr
のコンストラクタは、明確でアクセス可能な(すなわち、public継承が必須である)
enable_shared_from_this
基底クラスの存在を検出し、新しく作成された
std::shared_ptr
を、既に有効な
std::shared_ptr
によって所有されていない場合に
weak_this
に割り当てます。既に他の
std::shared_ptr
によって管理されているオブジェクトに対して
std::shared_ptr
を構築すると、
weak_this
は参照されず、未定義動作を引き起こします。
shared_from_this
を呼び出すことが許可されているのは、事前に共有されたオブジェクト、すなわち
std::
shared_ptr
<
T
>
によって管理されているオブジェクトのみです。それ以外の場合、
std::bad_weak_ptr
がスローされます(デフォルト構築された
weak_this
からの
std::shared_ptr
コンストラクタによって)。
enable_shared_from_this
は、
std::
shared_ptr
<
T
>
(
this
)
のような式に対する安全な代替手段を提供します。この式は、互いに認識していない複数の所有者によって
this
が複数回破棄される可能性が高いためです(以下の例を参照)。
例
#include <iostream> #include <memory> class Good : public std::enable_shared_from_this<Good> { public: std::shared_ptr<Good> getptr() { return shared_from_this(); } }; class Best : public std::enable_shared_from_this<Best> { struct Private{ explicit Private() = default; }; public: // コンストラクタはこのクラスからのみ使用可能 Best(Private) {} // 他のすべてのコードはこのファクトリ関数を使用する必要がある // したがって、すべてのBestオブジェクトはshared_ptr内に格納される static std::shared_ptr<Best> create() { return std::make_shared<Best>(Private()); } std::shared_ptr<Best> getptr() { return shared_from_this(); } }; struct Bad { std::shared_ptr<Bad> getptr() { return std::shared_ptr<Bad>(this); } ~Bad() { std::cout << "Bad::~Bad() called\n"; } }; void testGood() { // Good: 2つのshared_ptrが同じオブジェクトを共有している std::shared_ptr<Good> good0 = std::make_shared<Good>(); std::shared_ptr<Good> good1 = good0->getptr(); std::cout << "good1.use_count() = " << good1.use_count() << '\n'; } void misuseGood() { // Bad: shared_from_thisが呼び出されたが、std::shared_ptrが呼び出し元を所有していない try { Good not_so_good; std::shared_ptr<Good> gp1 = not_so_good.getptr(); } catch (std::bad_weak_ptr& e) { // 未定義動作(C++17まで)およびstd::bad_weak_ptrスロー(C++17以降) std::cout << e.what() << '\n'; } } void testBest() { // Best: 同じだがスタック割り当てできない: std::shared_ptr<Best> best0 = Best::create(); std::shared_ptr<Best> best1 = best0->getptr(); std::cout << "best1.use_count() = " << best1.use_count() << '\n'; // Best stackBest; // <- Best::Best()がprivateなのでコンパイルされない } void testBad() { // Bad: 各shared_ptrがオブジェクトの唯一の所有者であると考えている std::shared_ptr<Bad> bad0 = std::make_shared<Bad>(); std::shared_ptr<Bad> bad1 = bad0->getptr(); std::cout << "bad1.use_count() = " << bad1.use_count() << '\n'; } // 未定義動作: Badの二重削除 int main() { testGood(); misuseGood(); testBest(); testBad(); }
出力例:
good1.use_count() = 2 bad_weak_ptr best1.use_count() = 2 bad1.use_count() = 1 Bad::~Bad() called Bad::~Bad() called *** glibc detected *** ./test: double free or corruption
欠陥報告
以下の動作変更の欠陥報告書は、以前に公開されたC++規格に対して遡及的に適用されました。
| DR | 適用対象 | 公開時の動作 | 正しい動作 |
|---|---|---|---|
|
LWG 2179
( P0033R1 ) |
C++11 |
enable_shared_from_this
から派生した型
T
が与えられた場合、
同じ T * オブジェクトから2つの std:: shared_ptr < T > を構築する動作が不明確であった |
この場合の動作は
未定義である |
|
LWG 2529
( P0033R1 ) |
C++11 | 基盤となる std::weak_ptr がどのように更新されるか不明確であった | 明確化された |
関連項目
|
(C++11)
|
共有オブジェクト所有権セマンティクスを持つスマートポインタ
(クラステンプレート) |
|
新しいオブジェクトを管理する共有ポインタを作成する
(関数テンプレート) |