Was ist der Zweck von std :: launder?

242

P0137 führt die Funktionsvorlage ein std::launderund nimmt in den Abschnitten zu Gewerkschaften, Lebensdauer und Zeigern viele, viele Änderungen am Standard vor.

Was ist das Problem, das dieses Papier löst? Was sind die Änderungen an der Sprache, die ich beachten muss? Und was machen wir launder?

Barry
quelle
2
Fragen Sie nach dem Papier selbst oder nach 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."
txtechhelp
7
nützlicher Link zum Thema. Auch diese Frage stackoverflow.com/questions/27003727/…
Paul Rooney
Dies wurde jetzt in VC2017 in Version 15.7.0
Damian
Nach dem Standard sind Zeiger triviale Typen, sodass das Waschen nichts bewirkt. ;)
neugieriger Kerl

Antworten:

250

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.

Nicol Bolas
quelle
34
Ist mein tl; dr also richtig: "Waschen ist im Grunde genommen für Nicht-UB-Typ-Punning"?
Druckermanly
13
Können Sie erklären, warum dies wahr ist? "Da nes sich um eine constVariable handelt, kann der Compiler davon ausgehen, dass diese u.x.nimmer 1 sein soll." Wo steht im Standard das? Ich frage, weil genau das Problem, auf das Sie hingewiesen haben, mir zu implizieren scheint, dass es überhaupt falsch ist. Es sollte nur unter der Als-ob-Regel wahr sein, die hier fehlschlägt. Was vermisse ich?
user541686
10
@Mehrdad [basic.life] / 8: " Wenn [...] ein neues Objekt an dem Speicherort erstellt wird, an dem das ursprüngliche Objekt [...] belegt war, verweist der Name des ursprünglichen Objekts automatisch auf das neue Objekt [...] wenn: [...] der Typ [...] kein nicht statisches Datenelement enthält, dessen Typ const-qualifiziert ist, oder einen Referenztyp [...] "
ecatmur
14
@ Barry Sehr; Wenn sich an der Adresse keine Objekte vom Typ T befinden ptr, brechen Sie die launderVorbedingung, sodass es keinen Sinn macht, über das Ergebnis zu sprechen.
TC
17
@NicolBolas Man kann nur hoffen, dass Supercat so viel Lobbyarbeit für die Komitees leistet, wie sie endlos Antworten von anderen Drittbenutzern auf SO fordern. Außerdem wird eine gute optimierenden Compiler Ihre korrekte Lösung optimiert memcpyin eine direkten Umdeutung zu unterstützten (dh lax Ausrichtung) Plattformen sowieso .
underscore_d