std::allocate_shared、std::allocate_shared_for_overwrite
| ヘッダ <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, |
(4) | (C++20以降) |
| template< class T, class Alloc > shared_ptr<T> allocate_shared( const Alloc& alloc, |
(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, |
(7) | (C++20以降) |
alloc のコピーを使用してオブジェクトのメモリを割り当て、指定された引数でオブジェクトを初期化します。新しく作成されたオブジェクトを管理する std::shared_ptr オブジェクトを返します。
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) のように破棄されます。
Alloc 型であり、alloc の再バインドされる可能性のあるコピーです。|
このオーバーロードは、 |
(C++20以降) |
T が未制限の配列型の場合にのみオーバーロード解決に参加します。T 型です。各要素はデフォルトで初期化されます。T が制限付き配列型の場合にのみオーバーロード解決に参加します。T が未制限の配列型の場合にのみオーバーロード解決に参加します。T 型です。各要素は初期値 u で初期化されます。T が制限付き配列型の場合にのみオーバーロード解決に参加します。T 型です。Tが配列型でない場合、オブジェクトは ::new (pv) T のように構築されます。ここで、pv はT型のオブジェクトを格納するのに適したストレージへの void* ポインタです。オブジェクトが破棄される場合、pt はそのオブジェクトへのT型のポインタであり、pt->~T() のように破棄されます。Tが制限付き配列型の場合、各要素の初期値は未指定です。
T が配列型でないか、または制限付き配列型の場合にのみオーバーロード解決に参加します。T が未制限の配列型の場合にのみオーバーロード解決に参加します。
配列要素の初期化と破棄以下の説明では、a は 型
2,3) std::allocator_traits<Alloc>::construct(a, pu)
4,5) std::allocator_traits<Alloc>::construct(a, pu, u)
6,7) ::new (pv) U
戻り値の std::shared_ptr によって管理されるオブジェクトの寿命が終了するか、配列要素の初期化中に例外がスローされた場合、初期化された要素は元の構築順と逆順に破棄されます。 非配列型 6,7) pu->~U()、ここで pu は
U 型のその配列要素へのポインタです。 |
(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以降)、 |
(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_overwrite、std::make_shared_for_overwrite、std::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 メンバ関数) | |
| 新しいオブジェクトを管理する共有ポインタを作成します (関数テンプレート) |