名前空間
変種
操作

std::allocate_shared、std::allocate_shared_for_overwrite

From cppreference.com
< cpp‎ | memory‎ | shared ptr
 
 
メモリ管理ライブラリ
(説明用*)
未初期化メモリのアルゴリズム
(C++17)
(C++17)
(C++17)
制約付き未初期化
メモリアルゴリズム
Cライブラリ

アロケータ
メモリリソース
ガベージコレクションのサポート
(C++11)(C++23まで)
(C++11)(C++23まで)
(C++11)(C++23まで)
(C++11)(C++23まで)
(C++11)(C++23まで)
(C++11)(C++23まで)
未初期化ストレージ
(C++20まで*)
(C++20まで*)
明示的な生存期間管理
 
 
ヘッダ <memory> で定義
template< class T, class Alloc, class... Args >
shared_ptr<T> allocate_shared( const Alloc& alloc, Args&&... args );
(1) (C++11以降)
template< class T, class Alloc >
shared_ptr<T> allocate_shared( const Alloc& alloc, std::size_t N );
(2) (C++20以降)
template< class T, class Alloc >
shared_ptr<T> allocate_shared( const Alloc& alloc );
(3) (C++20以降)
template< class T, class Alloc >

shared_ptr<T> allocate_shared( const Alloc& alloc, std::size_t N,

                               const std::remove_extent_t<T>& u );
(4) (C++20以降)
template< class T, class Alloc >

shared_ptr<T> allocate_shared( const Alloc& alloc,

                               const std::remove_extent_t<T>& u );
(5) (C++20以降)
template< class T, class Alloc >
shared_ptr<T> allocate_shared_for_overwrite( const Alloc& alloc );
(6) (C++20以降)
template< class T, class Alloc >

shared_ptr<T> allocate_shared_for_overwrite( const Alloc& alloc,

                                             std::size_t N );
(7) (C++20以降)

alloc のコピーを使用してオブジェクトのメモリを割り当て、指定された引数でオブジェクトを初期化します。新しく作成されたオブジェクトを管理する std::shared_ptr オブジェクトを返します。

1) オブジェクトは T 型で、std::allocator_traits<Alloc>::construct
    (a, pt, (std::forward<Args>(args)...)
のように構築されます。ここで、pt は、std::remove_cv_t<T> 型のオブジェクトを格納するのに適したストレージへの const std::remove_cv_t<T>* ポインタです。オブジェクトが破棄される場合、pt はそのオブジェクトへの std::remove_cv_t<T> 型のポインタであり、std::allocator_traits<Alloc>::destroy(a, pt) のように破棄されます。
上記の説明において、aAlloc 型であり、alloc の再バインドされる可能性のあるコピーです。

このオーバーロードは、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 のように構築されます。ここで、pvT 型のオブジェクトを格納するのに適したストレージへの void* ポインタです。オブジェクトが破棄される場合、pt はそのオブジェクトへの T 型のポインタであり、pt->~T() のように破棄されます。
  • T が制限付き配列型の場合、各要素の初期値は未指定です。
このオーバーロードは、T が配列型でないか、または制限付き配列型の場合にのみオーバーロード解決に参加します。
7) オブジェクトは std::remove_extent_t<T>[N] 型です。各要素の初期値は未指定です。
このオーバーロードは、T が未制限の配列型の場合にのみオーバーロード解決に参加します。

目次

配列要素の初期化と破棄

以下の説明では、aAlloc 型であり、alloc の再バインドされる可能性のあるコピーです。

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

  • U が配列型でない場合、各要素は、puU 型のオブジェクトを格納するのに適したストレージへの std::remove_cv_t<U>* ポインタであり、pvU 型のオブジェクトを格納するのに適したストレージへの void* ポインタであると仮定して、以下の式のように構築されます。
2,3) std::allocator_traits<Alloc>::construct(a, pu)
4,5) std::allocator_traits<Alloc>::construct(a, pu, u)
6,7) ::new (pv) U
  • それ以外の場合は、各要素の配列を再帰的に初期化します。次の次元では
  • Ustd::remove_extent_t<U> になります。
  • オーバーロード (4,5) では、uu の対応する要素になります。

戻り値の std::shared_ptr によって管理されるオブジェクトの寿命が終了するか、配列要素の初期化中に例外がスローされた場合、初期化された要素は元の構築順と逆順に破棄されます。

非配列型 U の各配列要素を破棄する場合、以下の式のように破棄されます。

2-5) std::allocator_traits<Alloc>::destroy(a, pu)、ここで puU 型のその配列要素への U* ポインタです。
6,7) pu->~U()、ここで puU 型のその配列要素へのポインタです。
(C++20以降)

[編集] パラメータ

alloc - 使用するAllocator
args... - T のインスタンスを構築するために使用される引数のリスト
N - 使用する配列サイズ
u - 配列の各要素を初期化するために使用される初期値

[編集] 戻り値

T 型のオブジェクトへの std::shared_ptrまたは T が未制限の配列型の場合は std::remove_extent_t<T>[N](C++20以降)

返された std::shared_ptr r について、r.get() はヌルでないポインタを返し、r.use_count()1 を返します。

[編集] 例外

Alloc::allocate() または T のコンストラクタからスローされる例外をスローする可能性があります。例外がスローされた場合、(1) は効果がありません。配列の構築中に例外がスローされた場合、既に初期化された要素は逆順に破棄されます(C++20以降)

[編集] 注記

これらの関数は通常、内部のブックキーピング構造(参照カウントなど)を格納するために、sizeof(T) よりも多くのメモリを割り当てます。

std::make_shared と同様に、この関数は通常1回の割り当てのみを実行し、T オブジェクトと制御ブロックの両方を割り当てられたメモリブロックに配置します(標準はこれを推奨しますが、義務付けてはいません。既知の実装はすべてこれを行います)。alloc のコピーは制御ブロックの一部として格納されるため、共有および弱参照カウントがゼロに達したときにそれを解放するために使用できます。

std::shared_ptrコンストラクタとは異なり、std::allocate_shared は個別のカスタムデリータを受け入れません。指定されたアロケータは、制御ブロックと T オブジェクトの破棄、およびそれらの共有メモリブロックの解放に使用されます。

std::shared_ptr は配列型をサポートしますが(C++17以降)、std::allocate_shared はサポートしません。この機能は boost::allocate_shared によってサポートされています。

(C++20まで)

ポインタ ptr の型が U* であるコンストラクタが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 への代入はアトミックではなく、同じオブジェクトへの潜在的な同時アクセスと競合します。これにより、将来の shared_from_this() 呼び出しが、この生ポインタコンストラクタによって作成された std::shared_ptr と所有権を共有することを保証します。

上記のコードのテスト ptr->weak_this .expired() は、weak_this が既に所有者を示している場合に再割り当てされないことを確認します。このテストは C++17 から必須です。

機能テストマクロ 規格 機能
__cpp_lib_smart_ptr_for_overwrite 202002L (C++20) デフォルト初期化によるスマートポインタの作成(std::allocate_shared_for_overwritestd::make_shared_for_overwritestd::make_unique_for_overwrite);オーバーロード (6,7)

[編集]

#include <cstddef>
#include <iostream>
#include <memory>
#include <memory_resource>
#include <vector>
 
class Value
{
    int i;
public:
    Value(int i) : i(i) { std::cout << "Value(), i = " << i << '\n'; }
    ~Value() { std::cout << "~Value(), i = " << i << '\n'; }
    void print() const { std::cout << "i = " << i << '\n'; }
};
 
int main()
{
    // Create a polymorphic allocator using the monotonic buffer resource
    std::byte buffer[sizeof(Value) * 8];
    std::pmr::monotonic_buffer_resource resource(buffer, sizeof(buffer));
    std::pmr::polymorphic_allocator<Value> allocator(&resource);
 
    std::vector<std::shared_ptr<Value>> v;
 
    for (int i{}; i != 4; ++i)
        // Use std::allocate_shared with the custom allocator
        v.emplace_back(std::allocate_shared<Value>(allocator, i));
 
    for (const auto& sp : v)
        sp->print();
} //< All shared pointers will automatically clean up when they go out of scope.

出力

Value(), i = 0
Value(), i = 1
Value(), i = 2
Value(), i = 3
i = 0
i = 1
i = 2
i = 3
~Value(), i = 0
~Value(), i = 1
~Value(), i = 2
~Value(), i = 3

[編集] 不具合報告

以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。

DR 適用対象 公開された動作 正しい動作
LWG 3216 C++20 std::allocate_shared は常に
アロケータをオブジェクトの構築および破棄の前に再バインドします。
再バインドはオプションです
LWG 4024 C++20 std::allocate_shared_for_overwrite で構築されるオブジェクトがどのように破棄されるかは
不明瞭でした。
明確化された

[編集] 関連項目

新しい shared_ptr を構築する
(public メンバ関数) [編集]
新しいオブジェクトを管理する共有ポインタを作成します
(関数テンプレート) [編集]
English 日本語 中文(简体) 中文(繁體)