std::launderwird treffend benannt, allerdings nur, wenn Sie wissen, wofür es ist. Es führt Speicherwäsche durch .
Betrachten Sie das Beispiel in der Arbeit:
struct X { const int n; };
union U { X x; float f; };
...
U u = {{ 1 }};
Diese Anweisung führt eine aggregierte Initialisierung durch und initialisiert das erste Mitglied von Uwith {1}.
Da neine ist constvariabel, ist der Compiler frei davon ausgehen , dass u.x.nmuss immer 1 sein.
Was passiert also, wenn wir dies tun:
X *p = new (&u.x) X {2};
Da dies Xtrivial ist, müssen wir das alte Objekt nicht zerstören, bevor wir an seiner Stelle ein neues erstellen. Dies ist also ein vollkommen gesetzlicher Code. Das nMitglied des neuen Objekts ist 2.
Also sag mir ... was wird u.x.nzurückkehren?
Die offensichtliche Antwort lautet 2. Aber das ist falsch, da der Compiler davon ausgehen darf, dass sich eine echte constVariable (nicht nur eine const&, sondern eine deklarierte Objektvariable const) niemals ändern wird . Aber wir haben es einfach geändert.
[basic.life] / 8 beschreibt die Umstände, unter denen der Zugriff auf das neu erstellte Objekt über Variablen / Zeiger / Verweise auf das alte Objekt in Ordnung ist. Und ein constMitglied zu haben, ist einer der disqualifizierenden Faktoren.
Also ... wie können wir u.x.nrichtig darüber reden ?
Wir müssen unser Gedächtnis waschen:
assert(*std::launder(&u.x.n) == 2); //Will be true.
Geldwäsche wird verwendet, um zu verhindern, dass Personen nachverfolgen, woher Sie Ihr Geld haben. Die Speicherwäsche wird verwendet, um zu verhindern, dass der Compiler nachverfolgt, woher Sie Ihr Objekt haben, und um Optimierungen zu vermeiden, die möglicherweise nicht mehr zutreffen.
Ein weiterer disqualifizierender Faktor ist, wenn Sie den Typ des Objekts ändern. std::launderkann auch hier helfen:
aligned_storage<sizeof(int), alignof(int)>::type data;
new(&data) int;
int *p = std::launder(reinterpret_cast<int*>(&data));
[basic.life] / 8 sagt uns, dass Sie, wenn Sie ein neues Objekt im Speicher des alten Objekts zuweisen, nicht über Zeiger auf das alte auf das neue Objekt zugreifen können. laundererlaubt uns, das zu umgehen.
std::launder?std::launderwird verwendet, um "einen Zeiger auf ein Objekt zu erhalten, das im Speicher erstellt wurde, der von einem vorhandenen Objekt desselben Typs belegt wird, selbst wenn es Konstanten- oder Referenzelemente enthält."