13

Es scheint eine Übereinstimmung zu geben, dass Sie nicht willy nilly (ein int *) in ein char Array wegen der C++ Aliasing-Regeln zeigen.Ist die Platzierung neu gesetzlich erforderlich, um ein int in ein Char-Array zu setzen?

Von dieser anderen Frage - Generic char[] based storage and avoiding strict-aliasing related UB - scheint es, dass es möglich ist, Speicher durch Placement neu zu verwenden (wieder).

alignas(int) char buf[sizeof(int)]; 

void f() { 
    // turn the memory into an int: (??) from the POV of the abstract machine! 
    ::new (buf) int; // is this strictly required? (aside: it's obviously a no-op) 

    // access storage: 
    *((int*)buf) = 42; // for this discussion, just assume the cast itself yields the correct pointer value 
} 

So wird die obige Rechts C++ und wird die Platzierung neuer tatsächlich benötigt es legal zu machen?

+0

In Verbindung stehend: http://stackoverflow.com/questions/38862092/is-it-legal-to-alias-a-char-array-through-a-pointer-to-int –

+0

https://godbolt.org/g/k2nVI9 –

+0

Hoch relevant, potentiell betrogen: https://stackoverflow.com/questions/40873520/reinterpret-cast-creating-a-trivial-default-constructible-object –

Antwort

12

Ja, die Platzierung new ist erforderlich, andernfalls würden Sie striktes Aliasing verletzen (Zuweisung ist).

Ist das oben Genannte? Fast (obwohl es bei praktisch allen Implementierungen funktioniert). Der Zeiger, den Sie durch die Umwandlung erstellt haben, zeigt nicht auf das Objekt, da das (jetzt zerstörte) Array und das int-Objekt nicht pointer-interconvertible sind; Verwenden Sie std::launder((int*)buf), oder noch besser, verwenden Sie den Rückgabewert des Placements new.

+1

Das strikte Aliasing wird nicht durch 'reinterpret_cast (buf) = 42' verletzt, da es auf das neue' int'-Objekt als lvalue vom Typ 'int' zugreift. Pointer-Interconvertible ist anwendbar beim Konvertieren eines "Live" -Zeigers in einen anderen, nicht beim Konvertieren eines "toten" Poiners in ein Nicht-Objekt in ein Live-Zeiger. Edit: Ich bin mir nicht sicher, ob dort 'launder' benötigt wird; Die Regeln waren immer noch in Bewegung, als ich wusste. – Potatoswatter

+1

@Potatoswatter Welches neue int Objekt? Ich sprach über den Fall, in dem es keine vorherige Platzierung gab, um ein solches Objekt zu erstellen. Und ich lese die Pointerkonvertierbarkeit, wie sie allgemein bei der Neuinterpretation von Zeigern anwendbar ist. Ungeachtet dessen zeigt der Zeiger, der durch den Op mit der Besetzung erzeugt wurde, nicht auf das neue Objekt, wie es in P0137 definiert ist, so dass "Wässerung" notwendig sein sollte. – Columbo

+0

[basic.lval] verbietet den Zugriff auf ein Objekt außer durch lvalues ​​bestimmter Typen. Es geht nicht um die Frage, ob ein Objekt noch existiert. [basic.life]/6 in C++ 14 erlaubt die Zuweisung durch 'reininterpret_cast', um eine Lebenszeit zu beginnen; Dies wird durch P0137 entfernt, so dass C++ 17 (wahrscheinlich) Platzierungsneuheiten zu einer Anforderung machen wird. Sie haben Recht mit der Zeigerkonvertierbarkeit; P0137 verbindet es mit 'reinterpret_cast' über' static_cast' von 'void *'. Es ist also notwendig, auf das Live-Objekt zuzugreifen (aber niemals den Speicher auf ein Nicht-Objekt zu laden). – Potatoswatter

-3
*((int*)buf) = 42; 

schreibt ein int mit einem int lvalue, so gibt es kein Aliasing-Problem in erster Linie.

Verwandte Themen