Was ist der Zweck von std::launder?

Lesezeit: 8 Minuten

Was ist der Zweck von stdlaunder
Barry

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

Welches Problem löst dieses Papier? Welche Sprachänderungen muss ich beachten? Und was sind wir laundering?

  • Fragen Sie nach dem Papier selbst oder nach std::launder? std::launder wird verwendet, um “einen Zeiger auf ein Objekt zu erhalten, das im Speicher erstellt wurde und von einem vorhandenen Objekt desselben Typs belegt ist, selbst wenn es const- oder Referenzelemente hat.”

    – txtechhelp

    8. September 2016 um 4:25 Uhr


  • sinnvoll Verknüpfung zum Thema. Auch diese Frage stackoverflow.com/questions/27003727/…

    – Paul Rooney

    8. September 2016 um 4:30 Uhr


  • Diese wurde nun in VC2017 in Version 15.7.0 veröffentlicht

    – Damian

    8. Mai 2018 um 0:47 Uhr

  • Laut std sind Zeiger triviale Typen, sodass Launder nichts bewirkt. 😉

    – Neugieriger

    1. Dezember 2018 um 10:26 Uhr

Was ist der Zweck von stdlaunder
Nicol Bola

std::launder ist treffend benannt, allerdings nur, wenn Sie wissen, wofür es ist. Es führt Gedächtniswäsche.

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 Aggregatinitialisierung durch und initialisiert das erste Mitglied von U mit {1}.

Weil n ist ein const Variable, kann der Compiler davon ausgehen u.x.n soll immer 1 sein.

Was passiert also, wenn wir dies tun:

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

Weil X trivial ist, müssen wir das alte Objekt nicht zerstören, bevor wir an seiner Stelle ein neues erstellen, also ist dies ein vollkommen legaler Code. Das neue Objekt wird seine haben n Mitglied sein 2.

Also sag mir… was wird u.x.n Rückkehr?

Die offensichtliche Antwort wird 2 sein. Aber das ist falsch, weil der Compiler davon ausgehen darf, dass a true ist const Variable (nicht nur eine const&sondern eine Objektvariable erklärt const) wird sich nie ändern. Aber wir haben es einfach geändert.

[basic.life]/8 buchstabiert die Umstände, wann es in Ordnung ist, auf das neu erstellte Objekt über Variablen/Zeiger/Referenzen auf das alte zuzugreifen. Und mit einem const Mitglied ist einer der disqualifizierenden Faktoren.

Also… wie können wir darüber reden u.x.n richtig?

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 nachvollziehen können, woher Sie Ihr Geld haben. Speicherwäsche wird verwendet, um dies zu verhindern Compiler davon abzuhalten, zu verfolgen, woher Sie Ihr Objekt haben, und es so zu zwingen, alle Optimierungen zu vermeiden, die möglicherweise nicht mehr gelten.

Ein weiterer disqualifizierender Faktor ist, wenn Sie die Art des Objekts ändern. std::launder kann hier auch helfen:

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

[basic.life]/8 teilt uns mit, dass Sie, wenn Sie ein neues Objekt im Speicher des alten zuweisen, nicht auf das neue Objekt durch Zeiger auf das alte zugreifen können. launder ermöglicht es uns, dem auszuweichen.

  • Ist mein tl; dr richtig: “Waschen ist im Grunde für Wortspiele vom Typ Nicht-UB”?

    – druckerman

    8. September 2016 um 5:16 Uhr

  • Können Sie erklären, warum das so ist? “Weil n ist ein const Variable, kann der Compiler davon ausgehen u.x.n immer 1 sein.” Wo steht das in der Norm? Ich frage, weil das Problem, auf das Sie hingewiesen haben, für mich zu implizieren scheint, dass es von vornherein falsch ist. Es sollte nur unter der Als-ob-Regel gelten, die hier versagt. Was vermisse ich?

    – Benutzer541686

    8. September 2016 um 8:39 Uhr

  • Wie weit können wir diese Aliasing-Regel umgehen? Wie template <class T, class U> T* alias_cast(U* ptr) { return std::launder(reinterpret_cast<T*>(ptr)); } Wie UB ist das?

    – Barri

    8. September 2016 um 13:49 Uhr

  • @Barry Sehr; wenn sich an der Adresse keine Objekte vom Typ T befinden ptr darstellt, dann brechen Sie launder‘s Voraussetzung, also macht es keinen Sinn, über das Ergebnis zu sprechen.

    – TC

    8. September 2016 um 17:52 Uhr

  • @NicolBolas Ein guter Optimierungscompiler optimiert Ihre korrekte Lösung von memcpy in eine In-Place-Neuinterpretation auf unterstützten (dh laxe Ausrichtung) Plattformen ohnehin.

    – Unterstrich_d

    12. September 2016 um 8:59 Uhr


Was ist der Zweck von stdlaunder
einpoklum

std::launder ist eine Fehlbezeichnung. Diese Funktion führt die Gegenteil der Wäsche: Es Böden den Speicher, auf den gezeigt wird, um jegliche Erwartung des Compilers bezüglich des Werts, auf den gezeigt wird, zu beseitigen. Es schließt jegliche Compiler-Optimierungen basierend auf solchen Erwartungen aus.

Daher könnte der Compiler in der Antwort von @NicolBolas davon ausgehen, dass ein Teil des Speichers einen konstanten Wert enthält. oder ist nicht initialisiert. Sie sagen dem Compiler: “Dieser Ort ist (jetzt) ​​verschmutzt, gehen Sie nicht davon aus.”

Wenn Sie sich fragen, warum der Compiler von vornherein immer an seinen naiven Erwartungen festhält und Sie dafür auffällig Dinge beschmutzen müssten, sollten Sie diese Diskussion lesen:

Warum `std::launder` einführen, anstatt den Compiler sich darum kümmern zu lassen?

… was mich zu dieser Ansicht von was führt std::launder bedeutet.

  • Ich weiß nicht, scheint mir genau zu waschen: Es entfernt die Herkunft des Zeigers, damit er sauber ist und (erneut) gelesen werden muss. Ich weiß nicht, was “Verschmutzung” in diesem Zusammenhang bedeutet.

    – Barri

    13. Februar 2021 um 15:00 Uhr

  • @Barry: Speicher, in den irgendjemand Sachen geworfen/geschrieben haben könnte, ist schmutzig, nicht sauber. Wenn ich Ihnen ein Kleidungsstück ohne Herkunftsangabe gebe – wer weiß, wo es gewesen ist? Sie würden es definitiv in den Korb für schmutzige Wäsche legen, um es zu waschen.

    – einpoklum

    13. Februar 2021 um 17:30 Uhr

  • I stimme zu std::launder wird genau umgekehrt benannt, wenn es um Geldwäsche geht, aber ich denke nicht, dass Sie sagen sollten, dass es die Erinnerung beschmutzt. Schmutziges Geld ist schmutzig, ob „gewaschen“ oder nicht, aber das Waschen lässt die Leute fälschlicherweise annehmen, dass es sauber ist. Schmutziges Gedächtnis ist schmutzig, ob std::laundered oder nicht, aber die Wäsche macht der Compiler Stop fälschlicherweise angenommen, dass es sauber ist.

    – benrg

    22. März 2021 um 19:52 Uhr

  • Betreff: “Dieser Ort ist jetzt verschmutzt, machen Sie nicht diese Annahme” – Oder “dieser Ort ist verschmutzt, bitte std::launder es”

    – Ted Lyngmo

    25. Juli 2021 um 9:13 Uhr

  • @benrg: Geld, das gewaschen wurde ist reinigen. Wenn nachgewiesen werden kann, dass jemand 7.500 $ gestohlen, gewaschen und dann das Geld verwendet hat, um einen Gebrauchtwagen für 7.500 $ zu kaufen, kann die Regierung das Auto beschlagnahmen, es sei denn, der Verkäufer des Autos war Beihilfe zum Diebstahl oder zur Geldwäsche. der Verkäufer wäre berechtigt, die $7.500 aus dem Verkauf einzubehalten.

    – Superkatze

    27. August 2021 um 19:56 Uhr

Ich denke, es gibt zwei Zwecke std::launder.

  1. Eine Barriere für konstante Faltung/Fortpflanzung, einschließlich Devirtualisierung.
  2. Eine Barriere für eine feinkörnige objektstrukturbasierte Aliasanalyse.

Barriere für überaggressive konstante Faltung / Ausbreitung (aufgegeben)

In der Vergangenheit erlaubte der C++-Standard Compilern anzunehmen, dass der Wert eines const-qualifizierten oder referenzierten nicht statischen Datenmembers, der auf gewisse Weise erhalten wurde, unveränderlich ist, selbst wenn sein enthaltendes Objekt nicht konstant ist und durch Platzierung neu wiederverwendet werden kann.

In C++17/P0137R1, std::launder wird als eine Funktionalität eingeführt, die die zuvor erwähnte (Fehl-)Optimierung (CWG 1776), was benötigt wird std::optional. Und wie besprochen in P0532R0portable Implementierungen von std::vector und std::deque kann auch brauchen std::launderauch wenn es sich um C++98-Komponenten handelt.

Glücklicherweise ist eine solche (Fehl-)Optimierung verboten RU007 (enthalten in P1971R0 und C++20). AFAIK gibt es keinen Compiler, der diese (Fehl-) Optimierung durchführt.

Barriere für Devirtualisierung

Ein virtueller Tabellenzeiger (vptr) kann während der Lebensdauer seines enthaltenden polymorphen Objekts, das für die Devirtualisierung benötigt wird, als konstant betrachtet werden. Da vptr kein nichtstatisches Datenelement ist, dürfen Compiler weiterhin eine Devirtualisierung auf der Grundlage der Annahme durchführen, dass vptr nicht geändert wird (d. h. entweder das Objekt noch in seiner Lebensdauer ist oder von einem neuen Objekt der wiederverwendet wird gleichen dynamischen Typs) in einigen Fällen.

Für einige ungewöhnliche Verwendungen, die ein polymorphes Objekt durch ein neues Objekt eines anderen dynamischen Typs ersetzen (gezeigt Hier), std::launder wird als Barriere für die Devirtualisierung benötigt.

IIUC Clang implementiert std::launder (__builtin_launder) mit dieser Semantik (LLVM-D40218).

Barriere für objektstrukturbasierte Aliasanalyse

P0137R1 ändert auch das C++-Objektmodell, indem es Zeiger-Interkonvertibilität einführt. Eine solche IIUC-Änderung ermöglicht eine „objektstrukturbasierte Aliasanalyse“, die in vorgeschlagen wird N4303.

Infolgedessen macht P0137R1 die direkte Verwendung der Dereferenzierung a reinterpret_cast‘d Zeiger von einem unsigned char [N] Array undefiniert, selbst wenn das Array Speicher für ein anderes Objekt des richtigen Typs bereitstellt. Und dann std::launder wird für den Zugriff auf das verschachtelte Objekt benötigt.

Diese Art der Alias-Analyse erscheint überaggressiv und kann viele nützliche Codebasen zerstören. AFAIK wird es derzeit von keinem Compiler implementiert.

Zusammenhang mit typbasierter Aliasanalyse/striktem Aliasing

IIUC std::launder und typbasierte Aliasanalyse/striktes Aliasing stehen in keinem Zusammenhang. std::launder erfordert, dass sich ein lebendes Objekt des richtigen Typs an der angegebenen Adresse befindet.

Es scheint jedoch, dass sie versehentlich in Clang (LLVM-D47607).

963050cookie-checkWas ist der Zweck von std::launder?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy