Namespaces
Variants

std:: make_shared, std:: make_shared_for_overwrite

From cppreference.net
Memory management library
( exposition only* )
Allocators
Uninitialized memory algorithms
Constrained uninitialized memory algorithms
Memory resources
Uninitialized storage (until C++20)
( until C++20* )
( until C++20* )
( until C++20* )

Garbage collector support (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
ヘッダーで定義 <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 オブジェクトを返します。

1) オブジェクトは型 T であり、 :: new ( pv ) T ( std:: forward < Args > ( args ) ... ) によって構築されるかのようである。ここで pv は型 T のオブジェクトを保持するのに適したストレージへの void * ポインタである。オブジェクトが破棄される場合、 pt - > ~T ( ) によって破棄されるかのようである。ここで pt は型 T のそのオブジェクトへのポインタである。

このオーバーロードは、 T が配列型でない場合にのみオーバーロード解決に参加する。

(C++20以降)
2) オブジェクトの型は std:: remove_extent_t < T > [ N ] です。各要素はデフォルト初期値を持ちます。
このオーバーロードは、 T が非制限配列型である場合にのみ、オーバーロード解決に参加します。
3) オブジェクトの型は T です。各要素はデフォルト初期値を持ちます。
このオーバーロードは、 T が有界配列型である場合にのみ、オーバーロード解決に参加します。
4) オブジェクトの型は std:: remove_extent_t < T > [ N ] です。各要素は初期値 u を持ちます。
このオーバーロードは、 T が非制限配列型である場合にのみ、オーバーロード解決に参加します。
5) オブジェクトの型は T です。各要素の初期値は u です。
このオーバーロードは、 T が有界配列型である場合にのみ、オーバーロード解決に参加します。
6) オブジェクトの型は T である。
  • T が配列型でない場合、オブジェクトは :: new ( pv ) T によって構築される。ここで pv は型 T のオブジェクトを保持するのに適したストレージを指す void * ポインタである。オブジェクトが破棄される場合、 pt - > ~T ( ) によって破棄される。ここで pt は型 T のそのオブジェクトを指すポインタである。
  • T が有界配列型の場合、各要素の初期値は未規定である。
このオーバーロードは、 T が配列型でない場合、または有界配列型である場合にのみ、オーバーロード解決に参加します。
7) オブジェクトの型は std:: remove_extent_t < T > [ N ] です。各要素の初期値は未指定です。
このオーバーロードは、 T が非制限配列型である場合にのみ、オーバーロード解決に参加します。

目次

配列要素の初期化と破棄

U の配列要素は、アドレスの昇順で初期化されます。

  • もし U が配列型でない場合、各要素は以下の式によって構築されます。ここで pv は型 U のオブジェクトを保持するのに適したストレージへの void * ポインタです:
2,3) :: new ( pv ) U ( )
4,5) :: new ( pv ) U ( u )
6,7) :: new ( pv ) U
  • それ以外の場合、各要素の要素を再帰的に初期化します。次の次元について:
  • U std:: remove_extent_t < U > になります。
  • オーバーロード (4,5) の場合、 u u の対応する要素になります。

返される std::shared_ptr によって管理されるオブジェクトの寿命が終了したとき、または配列要素の初期化が例外をスローしたとき、初期化された要素は元の構築順序の逆順で破棄されます。

破棄される非配列型 U の各配列要素について、それは pu - > ~U ( ) によって破棄されます。ここで pu は型 U のその配列要素へのポインタです。

(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... ) ) とは異なる動作になります。
  • std::shared_ptr は配列型をサポートします(C++17以降)が、 std::make_shared はサポートしません。この機能は boost::make_shared によってサポートされています。
(C++20まで)
  • 以下のようなコード f ( std:: shared_ptr < int > ( new int ( 42 ) ) , g ( ) ) は、 g new int ( 42 ) の後に呼び出されて例外をスローした場合、メモリリークを引き起こす可能性があります。一方、 f ( std :: make_shared < int > ( 42 ) , g ( ) ) は安全です。なぜなら、2つの関数呼び出しは 決してインターリーブされない からです。
(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)
オブジェクトが自身を参照する shared_ptr を作成できるようにする
(class template)
新しいオブジェクトを管理するunique pointerを作成する
(function template)
割り当て関数
(function)