P0137 は、関数テンプレートstd::launder
を導入し、ユニオン、ライフタイム、およびポインターに関するセクションの標準に多くの多くの変更を加えます。
このペーパーで解決している問題は何ですか?認識しなければならない言語の変更は何ですか?そしてlaunder
ingとは何ですか?
std::launder
は適切な名前が付けられていますが、その目的がわかっている場合のみです。 メモリロンダリングを実行します。
論文の例を考えてみましょう。
struct X { const int n; };
union U { X x; float f; };
...
U u = {{ 1 }};
このステートメントは、集約初期化を実行し、U
の最初のメンバーを{1}
で初期化します。
n
はconst
変数であるため、コンパイラーはu.x.n
がalwaysが1であると見なすことができます。
これを行うとどうなりますか:
X *p = new (&u.x) X {2};
X
は簡単なので、代わりに新しいオブジェクトを作成する前に古いオブジェクトを破棄する必要はないので、これは完全に合法なコードです。新しいオブジェクトのn
メンバーは2になります。
だから教えてください... u.x.n
は何を返しますか?
明らかな答えは2になります。しかし、コンパイラーは、const
変数(const&
だけでなく、オブジェクト変数が宣言されているconst
)は変更されません。しかし、変更しただけです。
[basic.life]/8 は、変数/ポインター/古いオブジェクトへの参照を介して、新しく作成されたオブジェクトにアクセスしてもよい場合の状況を示しています。 const
メンバーを持つことは、失格要因の1つです。
それで... u.x.n
について適切に話すにはどうすればよいですか?
私たちは記憶を洗濯しなければなりません:
assert(*std::launder(&u.x.n) == 2); //Will be true.
マネーロンダリングは、人々がお金をどこから得たのか追跡できないようにするために使用されます。メモリロンダリングは、compilerがオブジェクトを取得した場所をトレースしないようにするために使用されます。
もう1つの不適格要因は、オブジェクトのタイプを変更した場合です。ここでもstd::launder
が役立ちます:
aligned_storage<sizeof(int), alignof(int)>::type data;
new(&data) int;
int *p = std::launder(reinterpret_cast<int*>(&data));
[basic.life]/8 は、古いオブジェクトのストレージに新しいオブジェクトを割り当てると、古いオブジェクトへのポインターを介して新しいオブジェクトにアクセスできないことを示しています。 launder
を使用すると、それを回避できます。