std::shared_ptr<T>::shared_ptr - cppreference.com
<tbody> </tbody>
|
|
(1) | |
|
|
(2) | |
|
|
(3) | |
|
|
(4) | |
|
|
(5) | |
|
|
(6) | |
|
|
(7) | |
|
|
(8) | |
|
|
(8) | (C++20以上) |
|
|
(9) | |
|
|
(9) | |
|
|
(10) | |
|
|
(10) | |
|
|
(11) | |
|
|
(12) | (C++17で削除) |
|
|
(13) | |
管理するオブジェクトを参照する様々なポインタ型から新しい shared_ptr を構築します。
|
以下の説明において、ポインタ型 |
(C++17以上) |
1-2) 管理対象オブジェクトを持たない、すなわち空の shared_ptr を構築します。
3-7) 管理対象オブジェクトを指すポインタとして ptr を持つ shared_ptr を構築します。
|
|
(C++17未満) |
|
|
(C++17以上) |
さらに、
3) デリータとして delete 式 delete ptr を使用します (C++17未満)T が配列型でなければ delete 式 delete ptr を使用し、 T が配列型であれば delete[] ptr を使用します (C++17以上)。 Y は完全型でなければなりません。 delete 式は well-formed でなければならず、 well-defined な動作を持たねばならず、いかなる例外も投げてはなりません。 さらに、このコンストラクタは、 delete 式が well-formed でない場合、オーバーロード解決に参加しません。 (C++17以上)
4-5) デリータとして指定されたデリータ d を使用します。 式 d(ptr) は well-formed でなければならず、 well-defined な動作を持たなければならず、いかなる例外も投げてはなりません。 d の構築および d からの格納されるデリータの構築は例外を投げてはなりません。
|
|
(C++17未満) |
|
さらに、これらのコンストラクタは、式 |
(C++17以上) |
6-7) (4-5) と同じですが、さらに内部使用のデータ確保のために alloc のコピーを使用します。 Alloc は Allocator でなければなりません。
8) エイリアシングコンストラクタ。 所有権情報を r の初期値と共有する shared_ptr を構築しますが、無関係の管理されていないポインタ ptr を保持します。 この shared_ptr がスコープ外に出る最後のグループの場合、 r によって元々管理されていたオブジェクトに対して、その格納されているデリータが呼ばれます。 しかし、この shared_ptr に対して get() を呼べば、常に ptr のコピーを返します。 ptr が r の管理するオブジェクトのメンバであるとか r.get() のエイリアス (つまりダウンキャスト) であるとかいった一般的なユースケースにおいて、この shared_ptr が存在する限りこの ptr が有効であり続けることを保証するのはプログラマの責任です。 右辺値を取る2つめのオーバーロードの場合、呼び出しの後 r は空となり r.get() == nullptr となります。 (C++20以上)
9) r によって管理されているオブジェクトの所有権を共有する shared_ptr を構築します。 r の管理しているオブジェクトがなければ、 *this の管理するオブジェクトもありません。 このテンプレートオーバーロードは、 Y* が T* に暗黙に変換可能 (C++17未満)と互換 (C++17以上)でなければ、オーバーロード解決に参加しません。
10) shared_ptr を r からムーブ構築します。 構築後、 *this は r のそれまでの状態のコピーを格納し、 r は空になり、その格納されているポインタはNULLになります。 このテンプレートオーバーロードは、 Y* が T* に暗黙に変換可能 (C++17未満)と互換 (C++17以上)でなければ、オーバーロード解決に参加しません。
11) r によって管理されているオブジェクトの所有権を共有する shared_ptr を構築します。 Y* は T* に暗黙に変換可能でなければなりません。 (C++17未満)このオーバーロードは、Y* が T* と互換である場合にのみ、オーバーロード解決に参加します。 (C++17以上) ちなみに、同じ目的に r.lock() を使用することもできます。 違いは、このコンストラクタは引数が空の場合に例外を投げますが、 std::weak_ptr<T>::lock() はその場合に空の std::shared_ptr を構築します。
12) r によって所有されていたオブジェクトを格納し所有する shared_ptr を構築します。 Y* は T* に変換可能でなければなりません。 構築後、 r は空になります。
13) r によって現在管理されているオブジェクトを管理する shared_ptr を構築します。 管理対象オブジェクトの将来の削除のために r と紐付くデリータが格納されます。 呼び出し後、 r が管理するオブジェクトはなくなります。
このオーバーロードは、 std::unique_ptr<Y, Deleter>::pointer が T* と互換でない場合、オーバーロード解決に参加しません。 r.get() がNULLポインタの場合、このオーバーロードはデフォルトコンストラクタ (1) と同等です。 |
(C++17以上) |
Deleter が参照型の場合、 shared_ptr(r.release(), std::ref(r.get_deleter()) と同等です。 そうでなければ、 shared_ptr(r.release(), r.get_deleter()) と同等です。
T が配列型でないとき、オーバーロード (3), (4), (6) は ptr で shared_from_this を有効化し、オーバーロード (13) は r.release() によって返されたポインタで shared_from_this を有効化します。
ノート
コンストラクタが U* 型のポインタ ptr で shared_from_this を有効化するとは、 U が曖昧でなくアクセス可能な (C++17以上) std::enable_shared_from_this の特殊化を基底クラスに持つかどうか調べ、もし持つのであれば以下の文を評価する、という意味です。
if (ptr != nullptr && ptr->weak_this.expired()) ptr->weak_this = std::shared_ptr<std::remove_cv_t<U>>(*this, const_cast<std::remove_cv_t<U>*>(ptr));
ただし weak_this は std::shared_from_this が持つ std::weak_ptr 型の隠された mutable なメンバです。 weak_this メンバの代入はアトミックでなく、同じオブジェクトに対するあらゆる潜在的な並行アクセスと衝突します。 これにより shared_from_this() の将来の呼び出しが、この生のポインタのコンストラクタによって作成された shared_ptr と、所有権を共有することが保証されます。
上記の説明用コード内の判定 ptr->weak_this.expired() は、すでに所有者がある場合に weak_this が再代入されないようにします。 C++17 以降この判定が要求されます。
生のポインタのオーバーロードは、その指す先のオブジェクトの所有権を仮定します。 そのため、 shared_ptr によってすでに管理されているオブジェクトに対して、生のポインタのオーバーロードを使用して shared_ptr を構築すると (shared_ptr(ptr.get()) など)、未定義動作に繋がりがちです。 そのオブジェクトが std::enable_shared_from_this から派生した型であってもです。
デフォルトコンストラクタが constexpr であるため、 static な shared_ptr は、いかなる動的非ローカル初期化が始まるよりも前に、静的非ローカル初期化の一部として初期化されます。 このため、 static オブジェクトのコンストラクタで shared_ptr を使用しても安全です。
C++11 および C++14 では、 std::shared_ptr<T> の std::unique_ptr<T[]> からの構築が有効です。
std::unique_ptr<int[]> arr(new int[1]); std::shared_ptr<int> ptr(std::move(arr));
shared_ptr は unique_ptr からそのデリータ (std::default_delete<T[]> オブジェクト) を取得するため、配列は正しく解放されます。
これは C++17 以降できません。 代わりに配列形式の std::shared_ptr<T[]> を使用するべきです。
引数
| ptr | - | 管理するオブジェクトを指すポインタ |
| d | - | オブジェクトを破棄するために使用するデリータ |
| alloc | - | 内部使用のデータ確保のために使用するアロケータ |
| r | - | 所有権を共有または取得する別のスマートポインタ |
例外
3) 要求される追加のメモリが取得できなければ std::bad_alloc。 他のエラーに対して処理系定義の例外を投げるかもしれません。 例外が発生した場合は delete ptr (C++17未満)T が配列型でなければ delete ptr、そうでなければ delete[] ptr (C++17以上) が呼ばれます。
4-7) 要求される追加のメモリが取得できなければ std::bad_alloc。 他のエラーに対して処理系定義の例外を投げるかもしれません。 例外が発生した場合は d(ptr) が呼ばれます。
11) r.expired() == true の場合 std::bad_weak_ptr。 この場合、コンストラクタは効果を持ちません。
12) 要求される追加のメモリが取得できなければ std::bad_alloc。 他のエラーに対して処理系定義の例外を投げるかもしれません。 例外が発生した場合、このコンストラクタは効果を持ちません。
13) 例外が発生した場合、コンストラクタは効果を持ちません。
例
#include <memory> #include <iostream> struct Foo { Foo() { std::cout << "Foo...\n"; } ~Foo() { std::cout << "~Foo...\n"; } }; struct D { void operator()(Foo* p) const { std::cout << "Call delete from function object...\n"; delete p; } }; int main() { { std::cout << "constructor with no managed object\n"; std::shared_ptr<Foo> sh1; } { std::cout << "constructor with object\n"; std::shared_ptr<Foo> sh2(new Foo); std::shared_ptr<Foo> sh3(sh2); std::cout << sh2.use_count() << '\n'; std::cout << sh3.use_count() << '\n'; } { std::cout << "constructor with object and deleter\n"; std::shared_ptr<Foo> sh4(new Foo, D()); std::shared_ptr<Foo> sh5(new Foo, [](auto p) { std::cout << "Call delete from lambda...\n"; delete p; }); } }
出力:
constructor with no managed object constructor with object Foo... 2 2 ~Foo... constructor with object and deleter Foo... Foo... Call delete from lambda... ~Foo... Call delete from function object... ~Foo..