web-dev-qa-db-ja.com

std :: launderの目的は何ですか?

P0137 は、関数テンプレートstd::launderを導入し、ユニオン、ライフタイム、およびポインターに関するセクションの標準に多くの多くの変更を加えます。

このペーパーで解決している問題は何ですか?認識しなければならない言語の変更は何ですか?そしてlaunderingとは何ですか?

201
Barry

std::launderは適切な名前が付けられていますが、その目的がわかっている場合のみです。 メモリロンダリングを実行します。

論文の例を考えてみましょう。

struct X { const int n; };
union U { X x; float f; };
...

U u = {{ 1 }};

このステートメントは、集約初期化を実行し、Uの最初のメンバーを{1}で初期化します。

nconst変数であるため、コンパイラーはu.x.nalwaysが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を使用すると、それを回避できます。

209
Nicol Bolas