std:: make_shared, std:: make_shared_for_overwrite
|
ヘッダーで定義
<memory>
|
||
|
template
<
class
T,
class
...
Args
>
shared_ptr < T > make_shared ( Args && ... args ) ; |
(1) | (C++11以降) |
|
template
<
class
T
>
shared_ptr < T > make_shared ( std:: size_t N ) ; |
(2) | (C++20以降) |
|
template
<
class
T
>
shared_ptr < T > make_shared ( ) ; |
(3) | (C++20以降) |
|
template
<
class
T
>
shared_ptr < T > make_shared ( std:: size_t N, const std:: remove_extent_t < T > & u ) ; |
(4) | (C++20以降) |
|
template
<
class
T
>
shared_ptr < T > make_shared ( const std:: remove_extent_t < T > & u ) ; |
(5) | (C++20以降) |
|
template
<
class
T
>
shared_ptr < T > make_shared_for_overwrite ( ) ; |
(6) | (C++20以降) |
|
template
<
class
T
>
shared_ptr < T > make_shared_for_overwrite ( std:: size_t N ) ; |
(7) | (C++20以降) |
オブジェクトのメモリを割り当て、指定された引数でオブジェクトを初期化します。新しく作成されたオブジェクトを管理する std::shared_ptr オブジェクトを返します。
T
であり、
::
new
(
pv
)
T
(
std::
forward
<
Args
>
(
args
)
...
)
によって構築されるかのようである。ここで
pv
は型
T
のオブジェクトを保持するのに適したストレージへの
void
*
ポインタである。オブジェクトが破棄される場合、
pt
-
>
~T
(
)
によって破棄されるかのようである。ここで
pt
は型
T
のそのオブジェクトへのポインタである。
|
このオーバーロードは、
|
(C++20以降) |
T
が非制限配列型である場合にのみ、オーバーロード解決に参加します。
T
です。各要素はデフォルト初期値を持ちます。
T
が有界配列型である場合にのみ、オーバーロード解決に参加します。
T
が非制限配列型である場合にのみ、オーバーロード解決に参加します。
T
です。各要素の初期値は
u
です。
T
が有界配列型である場合にのみ、オーバーロード解決に参加します。
T
である。
-
Tが配列型でない場合、オブジェクトは :: new ( pv ) T によって構築される。ここで pv は型Tのオブジェクトを保持するのに適したストレージを指す void * ポインタである。オブジェクトが破棄される場合、 pt - > ~T ( ) によって破棄される。ここで pt は型Tのそのオブジェクトを指すポインタである。 -
Tが有界配列型の場合、各要素の初期値は未規定である。
T
が配列型でない場合、または有界配列型である場合にのみ、オーバーロード解決に参加します。
T
が非制限配列型である場合にのみ、オーバーロード解決に参加します。
配列要素の初期化と破棄
型
2,3)
::
new
(
pv
)
U
(
)
4,5)
::
new
(
pv
)
U
(
u
)
6,7)
::
new
(
pv
)
U
返される std::shared_ptr によって管理されるオブジェクトの寿命が終了したとき、または配列要素の初期化が例外をスローしたとき、初期化された要素は元の構築順序の逆順で破棄されます。
破棄される非配列型
|
(C++20以降) |
パラメータ
| args | - |
T
型のオブジェクトを構築するための引数リスト
|
| N | - | 使用する配列サイズ |
| u | - | 配列の各要素を初期化するための初期値 |
戻り値
std::shared_ptr
型
T
のオブジェクトへの
または、もし
T
が非制限配列型の場合
std::
remove_extent_t
<
T
>
[
N
]
(C++20以降)
。
返される std::shared_ptr r について、 r. get ( ) は非nullポインタを返し、 r. use_count ( ) は 1 を返す。
例外
例外として
std::bad_alloc
または
T
のコンストラクタによって送出されるあらゆる例外を送出する可能性がある。例外が送出された場合、関数は何も効果を持たない。
配列の構築中に例外が送出された場合、すでに初期化された要素は逆順で破棄される。
(C++20以降)
注記
これらの関数は通常、参照カウントなどの内部管理構造を可能にするために、 sizeof ( T ) 以上のメモリを割り当てます。
これらの関数は、 std:: shared_ptr < T > ( new T ( args... ) ) の代替として使用できます。トレードオフは以下の通りです:
-
std::
shared_ptr
<
T
>
(
new T
(
args...
)
)
は少なくとも2回のメモリ確保(オブジェクト
T用とshared_ptrの制御ブロック用)を行う一方、 std :: make_shared < T > は通常1回のメモリ確保のみを行います(標準ではこれを推奨していますが必須ではなく、既知の実装はすべてこれを実装しています)。 -
すべてのshared所有者の寿命が終了した後も、
std::weak_ptr
が
std::make_sharedによって作成された制御ブロックを参照している場合、Tが占有するメモリはすべてのweak所有者が破棄されるまで解放されません。これは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まで) |
コンストラクタは
shared_from_this
を有効にし
、型
U*
のポインタ
ptr
を用いて、
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
への代入はアトミックではなく、同じオブジェクトへの潜在的な並行アクセスと競合します。これにより、将来の
shared_from_this()
の呼び出しが、この生ポインタコンストラクタによって作成された
std::shared_ptr
と所有権を共有することが保証されます。
上記のコードにおけるテスト
ptr
-
>
weak_this
.
expired
(
)
は、既に所有者を示している場合に
weak_this
が再割り当てされないことを保証します。このテストはC++17以降で必須要件となります。
| 機能テスト マクロ | 値 | 標準 | 機能 |
|---|---|---|---|
__cpp_lib_shared_ptr_arrays
|
201707L
|
(C++20) |
std::make_shared
の配列サポート; オーバーロード
(
2-5
)
|
__cpp_lib_smart_ptr_for_overwrite
|
202002L
|
(C++20) |
デフォルト初期化によるスマートポインタ作成 (
std::allocate_shared_for_overwrite
,
std::make_shared_for_overwrite
,
std::make_unique_for_overwrite
); オーバーロード
(
6,7
)
|
例
#include <iostream> #include <memory> #include <type_traits> #include <vector> struct C { // コンストラクタが必要 (C++20まで) C(int i) : i(i) {} C(int i, float f) : i(i), f(f) {} int i; float f{}; }; int main() { // 「sp1」の型に「auto」を使用 auto sp1 = std::make_shared<C>(1); // オーバーロード (1) static_assert(std::is_same_v<decltype(sp1), std::shared_ptr<C>>); std::cout << "sp1->{ i:" << sp1->i << ", f:" << sp1->f << " }\n"; // 「sp2」の型を明示的に指定 std::shared_ptr<C> sp2 = std::make_shared<C>(2, 3.0f); // オーバーロード (1) static_assert(std::is_same_v<decltype(sp2), std::shared_ptr<C>>); static_assert(std::is_same_v<decltype(sp1), decltype(sp2)>); std::cout << "sp2->{ i:" << sp2->i << ", f:" << sp2->f << " }\n"; // 値初期化された float[64] への shared_ptr; オーバーロード (2): std::shared_ptr<float[]> sp3 = std::make_shared<float[]>(64); // 値初期化された long[5][3][4] への shared_ptr; オーバーロード (2): std::shared_ptr<long[] (注:元のテキストは閉じ括弧のみのため、日本語でも同じ記号を保持します)[3] (注:元のテキストは閉じ括弧のみのため、日本語訳も同じ記号を保持します)[4] (注:元のテキストは閉じ括弧のみのため、日本語でも同じ記号を保持します)> sp4 = std::make_shared<long[] (注:元のテキスト「]」はHTMLタグ内の閉じ括弧であり、翻訳対象外のためそのまま保持されています)[3] (注:元のテキストは閉じ括弧のみのため、日本語でも同じ記号を保持します)[4]>(5); // 値初期化された short[128] への shared_ptr; オーバーロード (3): std::shared_ptr<short[128]> sp5 = std::make_shared<short[128]>(); // 値初期化された int[7][6][5] への shared_ptr; オーバーロード (3): std::shared_ptr<int[7][6][5]> sp6 = std::make_shared<int[7] (注:元のテキストは閉じ括弧のみのため、日本語でも同じ記号を保持します)[6][5]>(); // double[256]へのshared_ptr、各要素は2.0; オーバーロード (4): std::shared_ptr<double[]> sp7 = std::make_shared<double[]>(256, 2.0); // shared_ptr to a double[7][2], where each double[2] // element は {3.0, 4.0}; オーバーロード (4): std::shared_ptr<double[][2]> sp8 = std::make_shared<double[] (注:指定されたテキスト「]」はHTMLタグ内の閉じ括弧であり、翻訳対象外の要素となります。C++コードや専門用語を含まないため、そのまま保持します)[2] (注:元のテキストは閉じ括弧のみのため、日本語でも同じ記号を保持します)>(7, {3.0, 4.0}); // shared_ptr to a vector<int>[4], where each vector // 内容は {5, 6}; オーバーロード (4): std::shared_ptr<std::vector<int>[] (注:元のテキストは閉じ括弧のみのため、日本語でも同じ記号を保持します)> sp9 = std::make_shared<std::vector<int>[]>(4, {5, 6}); // float[512]へのshared_ptr、各要素は1.0; オーバーロード (5): std::shared_ptr<float[512] (注:元のテキストは閉じ括弧のみのため、日本語でも同じ記号を保持します)> spA = std::make_shared<float[512]>(1.0); // double[6][2]へのshared_ptr。各double[2]要素は // is {1.0, 2.0}; オーバーロード (5): std::shared_ptr<double[6][2] (注:元のテキストは閉じ括弧のみのため、日本語でも同じ記号を保持します)> spB = std::make_shared<double[6][2]>({1.0, 2.0}); // vector<int>[4]へのshared_ptr。各vectorは // 内容は {5, 6}; オーバーロード (5): std::shared_ptr<std::vector<int>[4]> spC = std::make_shared<std::vector<int>[4]>({5, 6}); }
出力:
sp1->{ i:1, f:0 }
sp2->{ i:2, f:3 }
不具合報告
以下の動作変更に関する欠陥報告書は、以前に公開されたC++規格に対して遡及的に適用されました。
| DR | 適用対象 | 公開時の動作 | 正しい動作 |
|---|---|---|---|
| LWG 4024 | C++20 |
std::make_shared_for_overwrite
で構築されたオブジェクトの
破棄方法が不明確であった |
明確化された |
関連項目
新しい
shared_ptr
を構築する
(public member function) |
|
|
アロケータを使用して割り当てられた新しいオブジェクトを管理するshared pointerを作成する
(function template) |
|
|
(C++11)
|
オブジェクトが自身を参照する
shared_ptr
を作成できるようにする
(class template) |
|
(C++14)
(C++20)
|
新しいオブジェクトを管理するunique pointerを作成する
(function template) |
|
割り当て関数
(function) |