Kann die Platzierung "neu" auf dem zugrunde liegenden Speicherwert beruhen?

8

Beginnen wir mit einem Kontext.

Ein benutzerdefinierter Speicherpool verwendete Code ähnlich dem folgenden:

%Vor%

Die Idee ist, dass ein Konstruktor, wenn er mit FastInitialization aufgerufen wird, annehmen könnte, dass der Speicher bereits auf Null initialisiert ist und daher nur die Mitglieder initialisiert, die einen anderen Wert benötigen.

GCC (zumindest 6.2 und 6.3) hat jedoch eine "interessante" Optimierung, die einsetzt.

%Vor%

Kompiliert nach:

%Vor%

Aber:

%Vor%

Kompiliert nach:

%Vor%

Das heißt, nur die ersten 16 Bytes von struct , der Teil, der seiner Basis entspricht, wurden initialisiert. Debugging-Informationen bestätigen, dass der Aufruf von memset(ptr, 0, sizeof(T)); vollständig entfernt wurde.

Auf der anderen Seite rufen sowohl ICC als auch Clang memset für die volle Größe auf, hier ist Clangs Ergebnis:

%Vor%

Also das Verhalten von GCC und Clang unterscheidet sich und die Frage wird: Ist GCC richtig und produziert bessere Assembly, oder ist Clang richtig und GCC Buggy?

Oder in Bezug auf die Sprachengesetzgebung:

Unter welchen Umständen kann sich ein Konstruktor auf den vorherigen Wert verlassen, der in seinem zugewiesenen Speicher gespeichert ist?

Hinweis: Ich nehme an, das ist nur wichtig mit dem Placement new , aber ich freue mich, dass es anders angezeigt wird.

    
Matthieu M. 27.01.2017, 09:29
quelle

2 Antworten

10
  

Mai Platzierung new beruhen auf zugrunde liegenden Speicherwert?

Nein, vielleicht nicht. Aus [dcl.init]:

  

Wenn für ein Objekt kein Initialisierer angegeben ist, wird das Objekt standardmäßig initialisiert. Wenn ein Objekt gespeichert werden soll   Wenn die automatische oder dynamische Speicherdauer erreicht wird, hat das Objekt einen unbestimmten Wert, und wenn für das Objekt keine Initialisierung ausgeführt wird, behält dieses Objekt einen unbestimmten Wert bei, bis dieser Wert ersetzt wird (5.18).

Unbestimmter Wert bedeutet genau das, unbestimmt. Es bedeutet nicht, dass im Falle eines neuen Placements der vorherige Speicher notwendigerweise beibehalten wird. Der Compiler darf alles tun, was er will - inklusive, aber nicht beschränkt auf nichts.

  

Unter welchen Umständen kann sich ein Konstruktor auf den vorherigen Wert verlassen, der in seinem zugewiesenen Speicher gespeichert ist?

Der folgende Absatz in [dcl.init] listet Fälle auf, in denen das Verhalten bei der Erzeugung eines unbestimmten Wertes nicht definiert ist, sondern nur mit vorzeichenlosen schmalen Zeichentypen.

Also, unter keinen Umständen.

    
Barry 27.01.2017, 20:08
quelle
1

Sowohl GCC als auch Clang sind korrekt. Wenn die (eigenen) Datenelemente von DerivedMemset nicht initialisiert bleiben, wird dies zu undefiniertem Verhalten führen, sobald auf ihre Werte zugegriffen wird. Daher erhält der Compiler die Lizenz zum Verlassen - gleich bevor der Konstruktor aufgerufen wird - jedes Bitmuster im Speicherbereich, der von diesen Feldern belegt wird.

    
Leon 27.01.2017 10:31
quelle