std::make_shared, std::make_shared_for_overwrite
ヘッダ <memory> で定義
|
||
template< class T, class... Args > shared_ptr<T> make_shared( Args&&... args ); |
(1) | (C++11以上) (T が配列でない場合) |
template<class T> shared_ptr<T> make_shared( std::size_t N ); |
(2) | (C++20以上) (T が U[] の場合) |
template<class T> shared_ptr<T> make_shared(); |
(3) | (C++20以上) (T が U[N] の場合) |
template<class T> shared_ptr<T> make_shared( std::size_t N, const std::remove_extent_t<T>& u ); |
(4) | (C++20以上) (T が U[] の場合) |
template<class T> shared_ptr<T> make_shared( const std::remove_extent_t<T>& u ); |
(5) | (C++20以上) (T が U[N] の場合) |
template<class T> shared_ptr<T> make_shared_for_overwrite(); |
(6) | (C++20以上) (T が U[] でない場合) |
template<class T> shared_ptr<T> make_shared_for_overwrite( std::size_t N ); |
(7) | (C++20以上) (T が U[] の場合) |
args
を T
のコンストラクタに対する引数リストとして使用して T
型のオブジェクトを構築し、それを std::shared_ptr にラップします。 オブジェクトは式 ::new (pv) T(std::forward<Args>(args)...) を用いたかのように構築されます。 ただし pv
は T
型のオブジェクトを保持するのに適した記憶域を指す内部的な void*
ポインタです。 記憶域は、一般的には、 shared_ptr の制御ブロックと T
オブジェクトの両方に対して1回で確保を行うため、 sizeof(T)
より大きくなります。 この関数によって呼ばれる std::shared_ptr
のコンストラクタは、 T
型の新たに構築されたオブジェクトを指すポインタで shared_from_this
を有効化します。 このオーバーロードは、T が配列型でない場合にのみ、オーバーロード解決に参加します。std::remove_all_extents_t<T>
型の非配列要素は配置 new 式 ::new(pv) std::remove_all_extents_t<T>() によって行われたかのように値初期化されます。 オーバーロード (2) は、最初の次元のサイズが N
の配列を作成します。 配列要素はそのアドレスの昇順に初期化され、生存期間を終えるときはその逆の順序で破棄されます。u
から初期化されます。 U
が配列型でなければ、これは (1) の場合と同じ配置 new 式で行われたかのように行われます。 そうでなければ、これは配列 (多次元かもしれない) のすべての非配列要素が u
内の対応する要素で (1) の場合と同じ配置 new 式で初期化されたかのように行われます。 オーバーロード (4) は、最初の次元のサイズが N
の配列を作成します。 配列要素はそのアドレスの昇順に初期化され、生存期間を終えるときはその逆順で破棄されます。いずれの場合においても、オブジェクト (または T
が配列型の場合は個々の要素) (C++20以上) は p->~X() によって破棄されます。 ただし p
はオブジェクトを指すポインタで X
はその型です。
目次 |
[編集] 引数
args | - | T のインスタンスを構築するための引数リスト
|
N | - | 使用する配列サイズ |
u | - | 配列のすべての要素を初期化するための初期値 |
[編集] 戻り値
T
型のインスタンスの std::shared_ptr。
[編集] 例外
std::bad_alloc または T
のコンストラクタによって投げられるあらゆる例外。 例外が投げられた場合、この関数は効果を持ちません。 配列の構築中に例外が投げられた場合、すでに初期化された要素は逆順で破棄されます。 (C++20以上)
[編集] ノート
この関数は std::shared_ptr<T>(new T(args...)) の代替として使用することができます。 トレードオフは以下の通りです。
- std::shared_ptr<T>(new T(args...)) は少なくとも2回の確保を行います (1回は
T
のオブジェクトのためで、1回は shared_ptr の制御ブロックのためです)。 std::make_shared<T> は一般的に1回しか確保を行いません。 (標準はそのように推奨していますが、要求はしていません。 すべての既知の実装はそれを行っています。) - すべての shared_ptr の生存期間が終わった後も、 std::weak_ptr が
std::make_shared
によって作成された制御ブロックを参照している場合、T
によって占められていたメモリは、すべての weak_ptr も同様に破棄されるまで、残り続けます。sizeof(T)
が大きい場合、これは望ましくないかもしれません。 - std::shared_ptr<T>(new T(args...)) は、それが可能な場所で実行された場合、
T
のパブリックでないコンストラクタを呼ぶことができます。std::make_shared
は、選択されたコンストラクタへのパブリックなアクセスを要求します。 - std::shared_ptr のコンストラクタと異なり、
std::make_shared
ではカスタムアロケータを使用できません。 -
std::make_shared
は ::new を使用します。 そのため、クラス特有の operator new を使用して何らかの特殊な動作を行っている場合、 std::shared_ptr<T>(new T(args...)) とは異なる動作になります。
|
(C++20未満) |
|
(C++17未満) |
コンストラクタが 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 以降この判定が要求されます。
[編集] 例
#include <iostream> #include <memory> #include <type_traits> struct C { C(int i) : i(i) {} // (C++20 未満では) コンストラクタが必要 int i; }; int main() { auto sp = std::make_shared<C>(12); static_assert(std::is_same_v<decltype(sp), std::shared_ptr<C>>); std::cout << sp->i << '\n'; }
出力:
12
[編集] 関連項目
新しい shared_ptr を構築します (パブリックメンバ関数) | |
アロケータを使用して確保した新しいオブジェクトを管理する shared_ptr を作成します (関数テンプレート) | |
(C++14)(C++20) |
新しいオブジェクトを管理する unique_ptr を作成します (関数テンプレート) |
確保関数 (関数) |