P0137は、関数テンプレートstd::launder
を導入し、 共用体、存続時間、およびポインターに関するセクションで標準に多くの多くの変更を加えます。
このペーパーが解決している問題は何ですか?私が認識しなければならない言語の変更は何ですか?そして、私たちは何をしているのlaunder
ですか?
P0137は、関数テンプレートstd::launder
を導入し、 共用体、存続時間、およびポインターに関するセクションで標準に多くの多くの変更を加えます。
このペーパーが解決している問題は何ですか?私が認識しなければならない言語の変更は何ですか?そして、私たちは何をしているのlaunder
ですか?
回答:
std::launder
それが何のためにあるかを知っている場合だけですが、適切に名前が付けられています。メモリロンダリングを実行します。
論文の例を考えてみましょう:
struct X { const int n; };
union U { X x; float f; };
...
U u = {{ 1 }};
このステートメントは、集計初期化を実行し、U
withの最初のメンバーを初期化し{1}
ます。
のでn
あるconst
変数は、コンパイラは、その前提として自由であるu.x.n
ものとし、常に 1になります。
これを行うとどうなりますか?
X *p = new (&u.x) X {2};
X
はささいなことなので、新しいオブジェクトを作成する前に古いオブジェクトを破棄する必要はないので、これは完全に正当なコードです。新しいオブジェクトのn
メンバーは2になります。
だから教えてください...何がu.x.n
返りますか?
明白な答えは2です。しかし、コンパイラは真のconst
変数(だけでconst&
はなく、宣言され たオブジェクト変数const
)は決して変更されないと想定することができるため、誤りです。しかし、変更しました。
[basic.life] / 8は、変数/ポインタ/古いオブジェクトへの参照を介して、新しく作成されたオブジェクトにアクセスしてもよい状況を詳しく説明しています。そして、const
会員を持つことは失格要因の一つです。
では... u.x.n
適切に話し合うにはどうすればよいですか?
私たちは自分の記憶を洗濯しなければなりません:
assert(*std::launder(&u.x.n) == 2); //Will be true.
マネーロンダリングは、お金をどこから取得したかを人々が追跡できないようにするために使用されます。メモリロンダリングは、コンパイラーがオブジェクトを取得した場所をトレースしないようにするために使用されます。これにより、適用されなくなる可能性のある最適化を回避することが強制されます。
失格要素のもう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
それを回避することができます。
n
はconst
変数であるため、コンパイラはu.x.n
常に1であると想定できます。」それは規格のどこにそれを言っていますか?あなたが指摘したまさにその問題は、そもそもそれが誤りであることを私に暗示するように思われるので、私は尋ねます。これは、ここで失敗するas-ifルールの下でのみ真であるべきです。何が欠けていますか?
ptr
表すT型のオブジェクトが存在しない場合は、launder
の前提条件を破るので、結果について話しても意味がありません。
memcpy
サポート(つまり、緩いアライメント)のプラットフォーム上でのインプレース再解釈にとにかく。
std::launder
尋ねていますか?std::launder
「constまたは参照メンバーがある場合でも、同じタイプの既存のオブジェクトによって占有されているストレージに作成されたオブジェクトへのポインターを取得する」ために使用されます。