P0137関数テンプレートを導入しstd::launder
、共用体、有効期間、ポインタに関するセクションで標準に多くの変更を加えます。
この論文が解決しようとしている問題は何ですか? 知っておくべき言語の変更点は何ですか? そして、私たちは何をしよlaunder
うとしているのですか?
ベストアンサー1
std::launder
適切な名前がついていますが、それが何のために使用されるかを知っている場合に限ります。メモリ ロンダリングを実行します。
論文の例を考えてみましょう。
struct X { const int n; };
union U { X x; float f; };
...
U u = {{ 1 }};
このステートメントは、集計の初期化を実行し、 の最初のメンバーをU
で初期化します{1}
。
n
は変数なので、コンパイラは が常にconst
1 であると想定できu.x.n
ます。
では、次のようにすると何が起こるでしょうか:
X *p = new (&u.x) X {2};
は簡単なのでX
、新しいオブジェクトを作成する前に古いオブジェクトを破棄する必要はないので、これは完全に合法的なコードです。新しいオブジェクトのn
メンバーは 2 になります。
それで教えてください...何がu.x.n
戻ってくるのでしょうか?
const
明らかな答えは 2 です。しかし、これは誤りです。なぜなら、コンパイラーは、真の変数 (単なる ではなく、 と宣言されたconst&
オブジェクト変数)はを決して変更しないと想定できるからです。しかし、私たちはそれを変更したのです。 const
[ベーシックライフ]/8新しく作成されたオブジェクトに、古いオブジェクトへの変数/ポインタ/参照を介してアクセスすることが許可される状況を詳しく説明します。メンバーがあることは、const
不適格要因の 1 つです。
それで...どうやってきちんと話せばいいのでしょうかu.x.n
?
私たちは記憶を洗浄しなければなりません。
assert(*std::launder(&u.x.n) == 2); //Will be true.
マネー ロンダリングは、お金の出所を追跡されないようにするために使用されます。メモリ ロンダリングは、コンパイラがオブジェクトの出所を追跡できないようにし、適用されなくなった最適化を強制的に回避するために使用されます。
失格要因のもう 1 つは、オブジェクトのタイプを変更する場合です。std::launder
ここでも役立ちます:
alignas(int) char data[sizeof(int)];
new(&data) int;
int *p = std::launder(reinterpret_cast<int*>(&data));
[ベーシックライフ]/8は、古いオブジェクトのストレージに新しいオブジェクトを割り当てた場合、古いオブジェクトへのポインターを介して新しいオブジェクトにアクセスできないことを示しています。launder
これを回避できます。