as-if Regel und Entfernen der Zuordnung

9

Die as- Wenn Regel "dem Compiler das Recht gibt, Ausdrücke zu optimieren oder neu anzuordnen, die unter bestimmten Regeln keinen Unterschied in der Ausgabe und Korrektheit eines Programms machen, wie z.

  

§1.9.5

     

Eine konforme Implementierung, die ein wohlgeformtes Programm ausführt, soll   produzieren das gleiche beobachtbare Verhalten wie eine der möglichen Ausführungen   der entsprechenden Instanz der abstrakten Maschine mit dem gleichen   Programm und die gleiche Eingabe.

Die cppreference URL, die ich oben verlinkt habe, erwähnt spezielle Regeln für die Werte flüchtiger Objekte sowie für "neue Ausdrücke" unter C ++ 14:

  

New-expression hat eine weitere Ausnahme von der as-if-Regel: den Compiler   kann Aufrufe an die ersetzbaren Zuordnungsfunktionen entfernen, auch wenn a   benutzerdefiniertes Ersetzen wird bereitgestellt und hat beobachtbare Nebenwirkungen.

Ich nehme an, dass "austauschbar" hier ist, worüber beispielsweise in

gesprochen wird
  

§18.6.1.1.2

     

Ersetzbar: Ein C ++ - Programm kann eine Funktion mit dieser Funktion definieren   Signatur, die die von C ++ definierte Standardversion ersetzt   Standardbibliothek.

Stimmt es, dass mem unten unter der Als-ob-Regel entfernt oder neu geordnet werden kann?

%Vor%

Gibt es eine Möglichkeit, sicherzustellen, dass es nicht entfernt wird und zwischen den oberen und unteren Codeblöcken bleibt? Ein gut platziertes volatiles (entweder / oder volatiles std :: array oder links von auto) kommt mir in den Sinn, aber da es kein mem gibt, denke ich, dass das unter dem as-if Regel.

Seitliche Notiz; Ich konnte Visual Studio 2015 nicht dazu bringen, mem und die Zuweisung überhaupt zu optimieren.

Klarstellung: Der Weg zu Beobachtung wäre, dass der Zuweisungsaufruf an das OS zwischen jedem I / O der beiden Blöcke liegt. Der Punkt ist für Testfälle und / oder versuchen, Objekte an neuen Standorten zugewiesen werden.

    
Johan Lundberg 20.01.2016, 18:40
quelle

1 Antwort

4

Ja; Nein. Nicht in C ++.

Die abstrakte Maschine von C ++ spricht überhaupt nicht von Systemzuweisungsaufrufen. Nur die Nebeneffekte eines solchen Aufrufs, die das Verhalten der abstrakten Maschine beeinflussen, werden durch C ++ fixiert, und selbst dann kann der Compiler noch etwas anderes tun, solange - wenn es zu dem gleichen beobachtbaren Verhalten seitens der. Führt Programm in der abstrakten Maschine.

In der abstrakten Maschine erstellt auto mem = std::make_unique<std::array<double, 5000000>>(); eine Variable mem . Wenn es verwendet wird, erhalten Sie Zugriff auf eine große Menge von double s, die in ein Array gepackt sind. Die abstrakte Maschine kann eine Ausnahme auslösen oder Ihnen die große Menge an double s zur Verfügung stellen. beides ist in Ordnung.

Beachten Sie, dass es ein legaler C ++ - Compiler ist, alle Zuweisungen durch new durch eine bedingungslose throw eines Zuweisungsfehlers zu ersetzen (oder nullptr für die No-throw-Versionen zurückgibt), aber das wäre eine schlechte Qualität von Implementierung.

In dem Fall, in dem es zugeordnet ist, sagt der C ++ - Standard nicht wirklich, wo es herkommt. Der Compiler kann beispielsweise ein statisches Array verwenden und den delete -Aufruf zu einem No-Op machen (beachten Sie, dass er möglicherweise alle Möglichkeiten zum Aufrufen von delete auf dem Puffer erkennt).

Als nächstes, wenn Sie ein statisches Array haben, wenn niemand es liest oder schreibt (und die Konstruktion kann nicht beobachtet werden), kann der Compiler es eliminieren.

Davon abgesehen hängt vieles davon davon ab, dass der Compiler weiß, was vor sich geht.

Ein Ansatz besteht also darin, es dem Compiler unmöglich zu machen, etwas zu wissen. Lassen Sie Ihren Code eine DLL laden, und übergeben Sie dann an den Stellen, an denen der Status bekannt sein soll, einen Zeiger auf unique_ptr an diese DLL.

Da der Compiler nicht über Laufzeit-DLL-Aufrufe optimieren kann, muss der Status der Variablen grundsätzlich so sein, wie Sie es erwarten.

Leider gibt es keinen Standard-Weg, um Code wie in C ++ dynamisch zu laden, also müssen Sie sich auf Ihr aktuelles System verlassen.

Diese DLL kann separat geschrieben werden, um ein Noop zu sein; Oder Sie können sogar einen externen Zustand untersuchen und die Daten basierend auf dem externen Status bedingt laden und an die DLL übergeben. Solange der Compiler nicht beweisen kann, dass ein externer Zustand auftritt, kann er nicht um die Aufrufe nicht herum optimiert werden. Setzen Sie diesen externen Zustand niemals.

Deklarieren Sie die Variable am Anfang des Blocks. Übergeben Sie einen Zeiger auf die gefälschte externe DLL, wenn Sie nicht initialisiert sind. Wiederholen Sie kurz vor der Initialisierung, danach. Dann mach es am Ende des Blocks, bevor du es zerstörst, .reset() it, dann mach es wieder.

    
Yakk 20.01.2016, 19:03
quelle

Tags und Links