1. ホーム
  2. c++

[解決済み】std::launderの目的は何ですか?

2022-03-29 09:19:27

質問

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

この論文が解決しようとしている問題は何なのか?注意しなければならない言語の変更は何なのか?そして、私たちは何をすればいいのか? launder を行うのでしょうか?

どのように解決するのですか?

std::launder という名前は、何のためにあるのかが分かっていれば、適切な名前だと思います。これは メモリロンダリング .

論文にある例を考えてみましょう。

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

U u = {{ 1 }};

このステートメントは、集約の初期化を行い U{1} .

なぜなら nconst という変数がある場合、コンパイラは自由に u.x.n とする。 常に は1である。

では、こうするとどうなるか。

X *p = new (&u.x) X {2};

なぜなら X は些細なことなので、新しいオブジェクトを作成する前に古いオブジェクトを破壊する必要はありません。新しいオブジェクトはその n のメンバは2です。

では、教えてください......どうなるんですか? u.x.n を返しますか?

明らかな答えは、2でしょう。しかし、それは間違っています。なぜなら、コンパイラは、本当に const 変数(単に const& でなく、オブジェクト変数 宣言 const ) は変わらない . でも、変えただけなんです。

[基本.生活]/8 は、新しく作成されたオブジェクトに、古いオブジェクトの変数/ポインタ/参照を通じてアクセスしてもよい状況を明示しています。そして const メンバは失格要因の一つである。

では...どうすれば u.x.n を正しく使うことができるでしょうか?

メモリロンダリングが必要なんです。

assert(*std::launder(&u.x.n) == 2); //Will be true.

マネーロンダリングは、どこからお金を手に入れたか追跡されるのを防ぐために使われます。メモリロンダリングは コンパイラ オブジェクトの入手先を追跡できないようにすることで、もはや適用されないかもしれない最適化を回避させる。

もうひとつの欠点は、オブジェクトの型を変更した場合です。 std::launder はここでも役に立ちます。

aligned_storage<sizeof(int), alignof(int)>::type data;
new(&data) int;
int *p = std::launder(reinterpret_cast<int*>(&data));

[基本.生活]/8 は、古いオブジェクトのストレージに新しいオブジェクトを割り当てた場合、古いオブジェクトへのポインタを通じて新しいオブジェクトにアクセスできないことを教えてくれています。 launder を使えば、それを回避することができます。