From 382c5a58f43a993659b3fe8bb6816fc28f2bcddc Mon Sep 17 00:00:00 2001 From: yoh Date: Sun, 22 Jan 2023 00:51:10 +0900 Subject: [PATCH] =?UTF-8?q?memory:=20P1132R8=20out=5Fptr=5Ft,out=5Fptr?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0(#1050)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lang/cpp23.md | 2 +- reference/memory.md | 11 +++ reference/memory/out_ptr.md | 80 ++++++++++++++++++++ reference/memory/out_ptr_t.md | 58 ++++++++++++++ reference/memory/out_ptr_t/op_constructor.md | 45 +++++++++++ reference/memory/out_ptr_t/op_destructor.md | 75 ++++++++++++++++++ reference/memory/out_ptr_t/op_pointer.md | 44 +++++++++++ reference/memory/out_ptr_t/op_voidpp.md | 59 +++++++++++++++ 8 files changed, 373 insertions(+), 1 deletion(-) create mode 100644 reference/memory/out_ptr.md create mode 100644 reference/memory/out_ptr_t.md create mode 100644 reference/memory/out_ptr_t/op_constructor.md create mode 100644 reference/memory/out_ptr_t/op_destructor.md create mode 100644 reference/memory/out_ptr_t/op_pointer.md create mode 100644 reference/memory/out_ptr_t/op_voidpp.md diff --git a/lang/cpp23.md b/lang/cpp23.md index 71f95f71d9..0ad5123c1e 100644 --- a/lang/cpp23.md +++ b/lang/cpp23.md @@ -193,7 +193,7 @@ C++23とは、2023年中に改訂される予定の、C++バージョンの通 ### メモリ -- [``](/reference/memory.md)に、出力ポインタと入出力ポインタの抽象である[`std::out_ptr`](/reference/memory/out_ptr.md.nolink)と[`std::inout_ptr`](/reference/memory/inout_ptr.md.nolink)を追加 +- [``](/reference/memory.md)に、レガシーC関数からスマートポインタへの直接出力をサポートする、スマートポインタアダプタ[`std::out_ptr`](/reference/memory/out_ptr.md)と[`std::inout_ptr`](/reference/memory/inout_ptr.md.nolink)を追加 - [`std::unique_ptr`](/reference/memory/unique_ptr.md)クラスを`constexpr`に対応 - [``](/reference/memory.md)に、オブジェクトの生存期間を開始することを明示する関数として、[`std::start_lifetime_as()`](/reference/memory/start_lifetime_as.md.nolink)と[`std::start_lifetime_as_array()`](/reference/memory/start_lifetime_as_array.md.nolink)を追加 - [``](/reference/bit.md)に、値のバイト入れ替え (エンディアン変換) を行う[`std::byteswap()`](/reference/bit/byteswap.md)関数を追加 diff --git a/reference/memory.md b/reference/memory.md index aa92020469..8bd2bd4f0b 100644 --- a/reference/memory.md +++ b/reference/memory.md @@ -90,6 +90,16 @@ | `auto_ptr` | 古い専有方式スマートポインタ(class template) | C++11から非推奨
C++17で削除 | +## スマートポインタアダプタ + +| 名前 | 説明 | 対応バージョン | +|------|------|-------| +| [`out_ptr_t`](memory/out_ptr_t.md) | スマートポインタへの出力サポート(class template) | C++23 | +| [`out_ptr`](memory/out_ptr.md) | スマートポインタへの出力サポートヘルパ関数(function template) | C++23 | +| [`inout_ptr_t`](memory/inout_ptr_t.md.nolink) | スマートポインタへの入出力サポート(class template) | C++23 | +| [`inout_ptr`](memory/inout_ptr.md.nolink) | スマートポインタへの入出力サポートヘルパ関数(function template) | C++23 | + + ## スマートポインタのアトミック操作 | 名前 | 説明 | 対応バージョン | @@ -138,3 +148,4 @@ - [P0718R2 Revising `atomic_shared_ptr` for C++20](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0718r2.html) - [P2051R0 C++ Standard Library Issues to be moved in Prague](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2051r0.html) - [P2186R2 Removing Garbage Collection Support](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2186r2.html) +- [P1132R8 out_ptr - a scalable output pointer abstraction](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1132r8.html) diff --git a/reference/memory/out_ptr.md b/reference/memory/out_ptr.md new file mode 100644 index 0000000000..e613eec812 --- /dev/null +++ b/reference/memory/out_ptr.md @@ -0,0 +1,80 @@ +# out_ptr +* memory[meta header] +* function template[meta id-type] +* std[meta namespace] +* cpp23[meta cpp] + +```cpp +namespace std { + template + auto out_ptr(Smart& s, Args&&... args); +} +``` + +## 概要 +2重ポインタ`T**`引数経由で新規確保リソースへのポインタを返すレガシーC関数に対して、出力されたポインタ値をスマートポインタ`s`に格納するアダプタ[`out_ptr_t`](out_ptr_t.md)を返すヘルパ関数。 + +C++標準スマートポインタ[`std::shared_ptr`](shared_ptr.md)や[`std::unique_ptr`](unique_ptr.md)を始め、互換インタフェースをもつ任意のスマートポインタ型`Smart`を取り扱える。 + + +説明用の`P`型を次のように定義する : + +- [`is_void_v`](/reference/type_traits/is_void.md)``が`false`ならば`Pointer` +- そうでなければ、`Smart::pointer`が有効な型名であれば`Smart::pointer` +- そうでなければ、`Smart::element_type*`が有効な型名であれば`Smart::element_type*` +- そうでなければ、[`pointer_traits`](pointer_traits.md)`::element_type*` + + +## 戻り値 +[`out_ptr_t`](out_ptr_t.md)`(s,` [`std::forward`](/reference/utility/forward.md)`(args)...)` + + +## 例 +### P1132R8引用 +```cpp example +// Legacy C APIs +error_num c_api_create_handle(int seed_value, int** p_handle); +void c_api_delete_handle(int* handle); + +// C++ program +#include + +struct resource_deleter { + void operator()(int* handle) { + c_api_delete_handle(handle); + } +}; + +int main() { + std::unique_ptr resource(nullptr); + error_num err = c_api_create_handle( + 24, std::out_ptr(resource) + ); + if (err == C_API_ERROR_CONDITION) { + // handle errors + } + // resource.get() the out-value from the C API function +} +``` +* std::out_ptr[color ff0000] + + +## バージョン +### 言語 +- C++23 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 関連項目 +- [`out_ptr_t`](out_ptr_t.md) +- [`shared_ptr`](shared_ptr.md) +- [`unique_ptr`](unique_ptr.md) + + +## 参照 +- [P1132R8 out_ptr - a scalable output pointer abstraction](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1132r8.html) diff --git a/reference/memory/out_ptr_t.md b/reference/memory/out_ptr_t.md new file mode 100644 index 0000000000..5a2dee0b09 --- /dev/null +++ b/reference/memory/out_ptr_t.md @@ -0,0 +1,58 @@ +# out_ptr_t +* memory[meta header] +* class template[meta id-type] +* std[meta namespace] +* cpp23[meta cpp] + +```cpp +namespace std { + template + class out_ptr_t; +} +``` + +## 概要 +2重ポインタ`T**`(=`Pointer*`)引数経由で新規確保リソースへのポインタを返すレガシーC関数に対して、取得されたポインタ値をスマートポインタに格納するアダプタクラス。 +アダプタオブジェクトの生成には、[`std::out_ptr()`](out_ptr.md)ヘルパ関数を利用する。 + +C++標準スマートポインタ[`std::shared_ptr`](shared_ptr.md)や[`std::unique_ptr`](unique_ptr.md)を始め、互換インタフェースをもつ任意のスマートポインタ型`Smart`を取り扱える。 + + +## テンプレートパラメータ制約 +`Pointer`はCpp17NullablePointer要件を満たすこと + + +## 適格要件 +`Smart`が[`shared_ptr`](shared_ptr.md)の特殊化かつ`sizeof...(Args) == 0`の場合、プログラムは不適格となる。 +(根拠説明は[デストラクタ](out_ptr_t/op_destructor.md)を参照のこと。) + + +## メンバ関数 + +| 名前 | 説明 | 対応バージョン | +|-----------------|----------------|----------------| +| [`(constructor)`](out_ptr_t/op_constructor.md) | コンストラクタ | C++23 | +| [`(destructor)`](out_ptr_t/op_destructor.md) | デストラクタ | C++23 | +| [`operator Pointer*()`](out_ptr_t/op_pointer.md) | `Pointer*`への暗黙変換 | C++23 | +| [`operator void**()`](out_ptr_t/op_voidpp.md) | `void**`への暗黙変換 | C++23 | + + +## バージョン +### 言語 +- C++23 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 関連項目 +- [`out_ptr()`](out_ptr.md) +- [`shared_ptr`](shared_ptr.md) +- [`unique_ptr`](unique_ptr.md) + + +## 参照 +- [P1132R8 out_ptr - a scalable output pointer abstraction](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1132r8.html) diff --git a/reference/memory/out_ptr_t/op_constructor.md b/reference/memory/out_ptr_t/op_constructor.md new file mode 100644 index 0000000000..d73d0961e8 --- /dev/null +++ b/reference/memory/out_ptr_t/op_constructor.md @@ -0,0 +1,45 @@ +# コンストラクタ +* memory[meta header] +* std[meta namespace] +* out_ptr_t[meta class] +* function[meta id-type] +* cpp23[meta cpp] + +```cpp +explicit out_ptr_t(Smart& smart, Args... args); // (1) +out_ptr_t(const out_ptr_t&) = delete; // (2) +``` + +## 概要 +- (1) : `out_ptr_t`オブジェクトの構築。 +- (2) : コピーコンストラクタ。コピー不可。 + + +## 効果 +(1) : `out_ptr_t`クラスの説明用メンバ変数`s`, `a`, `p`を下記の通り初期化する。 + +- `Smart&`型メンバ変数 : `s = smart;` +- `tuple`型メンバ変数 : `a =` [`std::forward`](/reference/utility/forward.md)`(args)...;` +- `Pointer`型メンバ : `p = {};` + + +## バージョン +### 言語 +- C++23 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 関連項目 +- [`out_ptr()`](../out_ptr.md) +- [`(destructor)`](op_destructor.md) +- [`operator Pointer*`](op_pointer.md) +- [`operator void**`](op_voidpp.md) + + +## 参照 +- [P1132R8 out_ptr - a scalable output pointer abstraction](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1132r8.html) diff --git a/reference/memory/out_ptr_t/op_destructor.md b/reference/memory/out_ptr_t/op_destructor.md new file mode 100644 index 0000000000..22946ceb0b --- /dev/null +++ b/reference/memory/out_ptr_t/op_destructor.md @@ -0,0 +1,75 @@ +# デストラクタ +* memory[meta header] +* std[meta namespace] +* out_ptr_t[meta class] +* function[meta id-type] +* cpp23[meta cpp] + +```cpp +~out_ptr_t(); +``` + +## 概要 +指定した`Smart`型スマートポインタに、レガシーC関数呼び出しにより取得されたポインタ値を格納する。 + +スマートポインタへのポインタ値格納には、`Smart::reset()`メンバ関数、もしくは`Smart`オブジェクト構築+ムーブ代入`operator=`が利用される。 + +- オブジェクト単位でカスタムデリータを管理する[`std::shared_ptr`](../shared_ptr.md)の場合、[`out_ptr_t`コンストラクタ](op_constructor.md)にてデリータオブジェクトを渡しておくことで、[`reset()`](../shared_ptr/reset.md)呼び出しの追加引数リストとして渡される。 +この動作は[`out_ptr_t`](../out_ptr_t.md)クラステンプレートの適格要件にて強制される。 +- 型レベルでカスタムデリータを管理する[`std::unique_ptr`](../unique_ptr.md)の場合、[`reset()`](../unique_ptr/reset.md)呼び出しには取得ポインタ値のみが渡される。 +- これ以外のスマートポインタ型では、同スマートポインタの動作セマンティクスに従う。 + + +## 効果 +説明用の`SP`型を下記の通り定義する : + +- `Smart::pointer`が有効な型名であれば`Smart::pointer` +- そうでなければ、`Smart::element_type*`が有効な型名であれば`Smart::element_type*` +- そうでなければ、[`pointer_traits`](../pointer_traits.md)`::element_type*` +- そうでなければ、`Pointer` + +[説明用メンバ変数](op_constructor.md)`s`, `a`, `p`を用いて、以下と同じ効果を持つ : + +- 式 `s.reset(static_cast(p),` [`std::forward`](/reference/utility/forward.md)`(args)...)` が適格ならば、 + + ```cpp + if (p) { + apply([&](auto&&... args) { + s.reset(static_cast(p), std::forward(args)...); }, std::move(a)); + } + ``` + * apply[link /reference/tuple/apply.md] + +- [`is_constructible_v`](/reference/type_traits/is_constructible.md)``が`true`ならば、 + + ```cpp + if (p) { + apply([&](auto&&... args) { + s = Smart(static_cast(p), std::forward(args)...); }, std::move(a)); + } + ``` + * apply[link /reference/tuple/apply.md] + +- そうでなければ、プログラムは不適格となる。 + + +## バージョン +### 言語 +- C++23 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 関連項目 +- [`out_ptr()`](../out_ptr.md) +- [`(constructor)`](op_constructor.md) +- [`operator Pointer*`](op_pointer.md) +- [`operator void**`](op_voidpp.md) + + +## 参照 +- [P1132R8 out_ptr - a scalable output pointer abstraction](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1132r8.html) diff --git a/reference/memory/out_ptr_t/op_pointer.md b/reference/memory/out_ptr_t/op_pointer.md new file mode 100644 index 0000000000..3154decf66 --- /dev/null +++ b/reference/memory/out_ptr_t/op_pointer.md @@ -0,0 +1,44 @@ +# operator Pointer* +* memory[meta header] +* std[meta namespace] +* out_ptr_t[meta class] +* function[meta id-type] +* cpp23[meta cpp] + +```cpp +operator Pointer*() const noexcept; +``` + +## 概要 +`Pointer`型の[説明用メンバ変数](op_constructor.md)へのポインタを取得する。 + + +## 事前条件 +`*this`の[`operator void**()`](op_voidpp.md)が呼び出されていないこと + + +## 戻り値 +[`addressof`](../addressof.md)`(const_cast(p))` + + +## 例外 +投げない + + +## バージョン +### 言語 +- C++23 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 関連項目 +- [`out_ptr()`](../out_ptr.md) + + +## 参照 +- [P1132R8 out_ptr - a scalable output pointer abstraction](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1132r8.html) diff --git a/reference/memory/out_ptr_t/op_voidpp.md b/reference/memory/out_ptr_t/op_voidpp.md new file mode 100644 index 0000000000..c903bd9a32 --- /dev/null +++ b/reference/memory/out_ptr_t/op_voidpp.md @@ -0,0 +1,59 @@ +# operator void** +* memory[meta header] +* std[meta namespace] +* out_ptr_t[meta class] +* function[meta id-type] +* cpp23[meta cpp] + +```cpp +operator void**() const noexcept; +``` + +## 概要 +`Pointer`型の[説明用メンバ変数](op_constructor.md)へのポインタ値を、`void**`型にキャストして取得する。 + + +## テンプレートパラメータ制約 +[`is_same_v`](/reference/type_traits/is_same.md)``が`false`であること + + +## 適格要件 +[`is_pointer_v`](/reference/type_traits/is_pointer.md)``が`true`であること + + +## 事前条件 +`*this`の[`operator Pointer*()`](op_pointer.md)が呼び出されていないこと + + +## 戻り値 +次のポインタ値`v`を返す : + +- 初期値`*v`は`static_cast(p)`と等価であり、かつ +- `*this`の後続変更に続かない`*v`の変更は、`static_cast(p) == *v`のように、`*this`[デストラクト中](op_destructor.md)の`p`の値に影響を与える。 + + +## 例外 +投げない + + +## 備考 +`*this`の生存期間外での`*v`へのアクセスは未定義動作 + + +## バージョン +### 言語 +- C++23 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 関連項目 +- [`out_ptr()`](../out_ptr.md) + + +## 参照 +- [P1132R8 out_ptr - a scalable output pointer abstraction](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1132r8.html)