Erlaubte Compiler-Optimierungen für Schleifen in C ++ 11

8

Ist ein C ++ 11-kompatibler Compiler erlaubt, diesen Code zu optimieren / zu transformieren von:

%Vor%

zu allem, was einer Endlosschleife entspricht:

%Vor%

Die obige Umwandlung ist sicherlich aus der Sicht eines Single-Thread-Programms gültig, aber das ist nicht der allgemeine Fall.

War diese Optimierung auch in pre-C ++ 11 erlaubt?

    
Martin 03.03.2013, 15:55
quelle

2 Antworten

13

Absolut.

Da x nicht als volatile markiert ist und ein lokales Objekt mit automatischer Speicherdauer und interner Verknüpfung zu sein scheint und das Programm es nicht modifiziert, sind die beiden Programme äquivalent.

Sowohl in C ++ 03 als auch in C ++ 11 geschieht dies durch die Als-ob-Regel, da der Zugriff auf ein nichtflüchtiges Objekt nicht als "Nebeneffekt" des Programms angesehen wird :

  

[C++11: 1.9/12]: Der Zugriff auf ein Objekt, das durch einen flüchtigen glvalue (3.10) gekennzeichnet ist, das Ändern eines Objekts, das Aufrufen einer Bibliotheks-E / A-Funktion oder das Aufrufen einer Funktion, die eine dieser Operationen ausführt, sind alle Nebeneffekte Änderungen im Status der Ausführungsumgebung. Die Auswertung eines Ausdrucks (oder eines Unterausdrucks) umfasst im Allgemeinen   beide Wertberechnungen (einschließlich der Bestimmung der Identität eines Objekts für die gl-Wert-Auswertung und des Abrufens eines Wertes, der zuvor einem Objekt für die Pr-Wert-Auswertung zugewiesen wurde) und die Einleitung von Nebenwirkungen. Wenn ein Aufruf einer Bibliotheks-E / A-Funktion zurückgegeben wird oder ein Zugriff auf ein flüchtiges Objekt ausgewertet wird, gilt der Nebeneffekt als abgeschlossen, obwohl einige externe Aktionen durch den Aufruf (wie die E / A selbst) oder durch den flüchtigen Zugriff impliziert sind möglicherweise noch nicht abgeschlossen.

C ++ 11 macht Platz für ein globales -Objekt, dessen Wert in einem Thread geändert werden soll, und dann für den neuen Wert, der in einem anderen gelesen wird:

  

[C++11: 1.10/3]: Der Wert eines Objekts, das für einen Thread T an einem bestimmten Punkt sichtbar ist, ist der Anfangswert des Objekts, ein Wert, der dem Objekt von T , oder einem Wert zugewiesen ist Objekt durch einen anderen Thread nach den folgenden Regeln.

Wenn Sie dies jedoch tun, ist Ihr Objekt nicht atomar:

  

[C++11: 1.10/21]: Die Ausführung eines Programms enthält ein Datenrennen, wenn es zwei widersprüchliche Aktionen in verschiedenen Threads enthält, von denen mindestens einer nicht atomar ist und keiner vor dem anderen auftritt. Ein solches Datenrennen führt zu undefiniertem Verhalten.

Und wenn nicht definiertes Verhalten aufgerufen wird, kann alles passieren .

Bootnote

  

[C++11: 1.10/25]: Eine Implementierung sollte sicherstellen, dass der letzte Wert (in Modifikationsreihenfolge), der durch eine atomare oder eine Synchronisationsoperation zugewiesen wurde, für alle anderen Threads in einem endlichen Zeitraum sichtbar wird.

Beachten Sie, dass das Objekt atomisch sein müsste (zB std::atomic<bool> ), um diese Garantie zu erhalten.

    
Lightness Races in Orbit 03.03.2013, 15:58
quelle
1

Dem Compiler wird erlaubt, irgendetwas mit diesen beiden Schleifen zu tun. Einschließlich Beenden des Programms. Weil Endlosschleifen ein undefiniertes Verhalten haben, wenn sie keine synchronisationsähnliche Operation ausführen (etwas tun, das eine Synchronisation mit einem anderen Thread oder einer anderen E / A erfordert), entsprechend der C ++ - Speichermodell :

  

Beachten Sie, dass dies bedeutet, dass ein Programm mit endloser Rekursion oder Endlosschleife (egal ob es als for-Anweisung oder durch Looping von goto oder anderweitig implementiert wurde) undefiniertes Verhalten hat.

    
Raedwald 04.12.2017 21:31
quelle

Tags und Links