Kann dies zu undefiniertem Verhalten führen?
%Vor% char
hat spezielle Regeln für das strikte Aliasing. Wenn ich char
anstelle von uint8_t
verwende, ist es immer noch Undefined Behavior? Was ändert sich noch?
Wie Mitglied DeadMG hervorgehoben hat, ist reinterpret_cast
implementierungsabhängig. Wenn ich stattdessen einen C-Style Cast (int32_t*)storage
verwende, was würde sich ändern?
Der von place new zurückgegebene Zeiger kann genauso wie UB-verursachend sein wie jeder andere Zeiger, wenn Aliasing-Überlegungen in diesen eingefügt werden. Es liegt in Ihrer Verantwortung, sicherzustellen, dass der Speicher, in den Sie das Objekt platziert haben, nicht mit Alias versehen ist, was nicht sein sollte.
In diesem Fall können Sie nicht davon ausgehen, dass uint8_t
ein Alias für char
ist und daher die speziellen Aliasregeln angewendet werden. Außerdem wäre es ziemlich sinnlos, ein Array von uint8_t
anstelle von char
zu verwenden, weil sizeof()
in char
und nicht in uint8_t
steht. Sie müssten die Größe selbst berechnen.
Außerdem ist der Effekt von reinterpret_cast
vollständig implementationsdefiniert, so dass der Code sicherlich keine eindeutige Bedeutung hat.
Um unangenehme Speicher-Hacks auf niedriger Ebene zu implementieren, muss der ursprüngliche Speicher nur durch char*
, void*
und T*
ersetzt werden, wobei T
der endgültige Zieltyp ist - in diesem Fall int
. , plus, was auch immer Sie sonst von einem T*
erhalten können, wenn T
eine abgeleitete Klasse ist und Sie diesen abgeleiteten Klassenzeiger in einen Zeiger auf base konvertieren. Alles andere verletzt striktes Aliasing und hallo nasale Dämonen.
Ihre Version mit der üblichen Platzierung ist wirklich in Ordnung.
Es gibt eine Interpretation 1 der §§ 3.8 / 1 und 3.8 / 4, wo Objekte von trivialen Typen auf Verlangen "verschwinden" und "erscheinen" können. Dies ist kein Freipass, der es erlaubt, Alias-Regeln zu ignorieren, also beachten Sie:
%Vor% Wenn Sie auf der anderen Seite die Zauberstäbe in Ihrem zweiten Schnipsel umgetauscht haben (d. h. neu interpretieren und zuerst schreiben), sind Sie auch nicht ganz sicher. Während der Interpretation können Sie den Schreibvorgang für ein neues std::uint32_t
-Objekt rechtfertigen, das den Speicher implizit wiederverwendet. Das nachfolgende Lesen hat die Form
und §3.8 / 5 sagt (Betonung meiner und äußerst relevant):
[...] nachdem die Lebensdauer eines Objekts beendet ist und vor dem Speicher, den das Objekt belegt hat, wiederverwendet oder freigegeben wird, jeder Zeiger, der auf den Speicherort verweist, an dem sich das Objekt befindet oder befand kann aber nur begrenzt verwendet werden. [...] Ein solcher Zeiger verweist auf den zugeordneten Speicher (3.7.4.2), und die Verwendung des Zeigers, als wäre der Zeiger vom Typ
void*
, ist wohldefiniert.
§3.8 / 6 ist das gleiche, aber in Referenz / glvalue-Form (wohl relevanter, da wir hier einen Namen und nicht einen Zeiger wiederverwenden, aber der Absatz ist aus dem Zusammenhang heraus schwerer zu verstehen). Siehe auch §3.8 / 7, die einen begrenzten Spielraum bietet, den ich in Ihrem Fall nicht für anwendbar halte.
Um die Dinge einfacher zu machen, ist das verbleibende Problem:
%Vor% Wenn der Typ des Speichers zufälligerweise einen einfachen oder unsignierten Zeichentyp enthält (zB hat storage
wirklich den Typ unsigned char[4]
), dann würde ich sagen, dass Sie eine Grundlage haben, um die Bildung eines Zeigers zu begründen. Verweis auf die Speicherung des neuen Objekts (möglicherweise später neu zu interpretieren). Siehe z.B. ¶¶ 5 und 6 wiederum, die eine explizite Escape-Klausel zur Bildung eines Zeigers / reference / glvalue und §1.8 Das C ++ - Objektmodell haben, das beschreibt, wie ein Objekt ein konstituierendes Array von Bytes beinhaltet. Die Regeln für die Zeigerkonvertierungen sollten einfach und unumstritten sein (zumindest im Vergleich ...).
1 : Es ist schwer abzuschätzen, wie gut diese Interpretation in der Community ankommt - ich habe sie auf der Boost-Mailingliste gesehen, wo es eine gewisse Skepsis gegenüber dieser war.
Tags und Links c++ language-lawyer strict-aliasing placement-new type-punning