compiler-specific

___ tag123languagelawyer ___ Für Fragen zu den Feinheiten formeller oder autoritativer Spezifikationen von Programmiersprachen und Umgebungen. ___ tag123movesemantics ___ Move semantics ist eine Programmiersprachenfunktion, die es ermöglicht, einen Kopiervorgang durch einen effizienteren "move" zu ersetzen, wenn das Quellobjekt ein temporäres oder ein anderweitig ablaufendes Objekt ist. ___ qstnhdr ___ C ++ 14 automatisch erkennen "return sollte std :: move" Situation verwenden ___ tag123c17 ___ C ++ 17 ist der Name des 2017 genehmigten C ++ - Standards. Er baut auf dem vorherigen C ++ 14-Standard auf und verbessert die Kernsprache und die Standardbibliothek sowie einige neue Sprachfunktionen. ___ tag123compilerspezifisch ___ hilf uns, dieses Wiki zu bearbeiten ___ answer48727897 ___

Das korrekte Verhalten ist move / copy. Sie möchten wahrscheinlich nur einen ordentlich aufgeräumten Scheck schreiben.

Die Formulierung in C ++ 17 lautet [class.copy.elision] / 3 und in C ++ 14 ist [class.copy] / 32 . Die spezifischen Wörter und die Formatierung sind unterschiedlich, aber die Regel ist die gleiche.

In C ++ 11 war der Regelwortlaut [class.copy] / 32 und wurde an die Kopierschutzregeln gebunden, wurde die Ausnahme für automatische lokale Speichervariablen in CWG 1579 als Fehlerbericht hinzugefügt. Compiler, die sich vor diesem Fehlerbericht befinden, würden sich als Kopie / Kopie verhalten. Da der Fehlerbericht jedoch gegen C ++ 11 spricht, würden Compiler, die die Änderung des Wortlauts implementieren, diese in allen Standardversionen implementieren.

Verwendung des C ++ 17-Wortlauts:

  

In den folgenden Copy-Initialization-Kontexten könnte anstelle einer Kopieroperation eine move-Operation verwendet werden:

     
  • Wenn der Ausdruck in einer return-Anweisung ein (eventuell geklammerter) ID-Ausdruck ist, der ein Objekt mit automatischer Speicherdauer im body oder parameter-declaration-clause der innersten umschließenden Funktion oder Lambda-Ausdruck deklariert, oder
  •   
  • [...]
  •   

Überladungsauflösung, um den Konstruktor für die Kopie auszuwählen, wird zuerst so ausgeführt, als ob das Objekt durch einen R-Wert bestimmt wäre. Wenn die erste Überladungsauflösung fehlschlägt oder nicht ausgeführt wurde, oder wenn der Typ des ersten Parameters des ausgewählten Konstruktors kein rvalue-Verweis auf den Objekttyp (möglicherweise cv-qualifiziert) ist, wird die Überladungsauflösung ausgeführt Betrachten wir das Objekt erneut als einen Wert.

In:

%Vor%

Wir treffen den ersten Punkt, also versuchen wir ein %code% mit einem rvalue vom Typ %code% zu initialisieren, was %code% ergibt. Das entspricht den hervorgehobenen Kriterien, also verwenden wir es und das Ergebnis ist ein Umzug.

In:

%Vor%

Wir treffen wieder die erste Kugel, aber die Überladungsauflösung findet %code% . Der erste Parameter des ausgewählten Konstruktors ist nicht ein rvalue-Verweis auf %code% (möglicherweise cv-qualifiziert), sodass wir die Überladungsauflösung erneut ausführen - und am Ende kopieren.

    
___ tag123c ___ C ++ ist eine universelle Programmiersprache. Es wurde ursprünglich als Erweiterung von C entworfen und behält eine ähnliche Syntax, ist aber jetzt eine komplett andere Sprache. Verwenden Sie dieses Tag für Fragen zu Code, der mit einem C ++ - Compiler kompiliert werden soll. ___ qstntxt ___

Mein Verständnis ist, dass in C ++ 17 das folgende Snippet das Richtige tun soll:

%Vor%

Das heißt, in C ++ 17 soll der Compiler sowohl %code% als auch %code% als rvalues ​​für die Zwecke der Überladungsauflösung in diesen beiden return-Anweisungen behandeln. In C ++ 14 und früher war dies jedoch nicht der Fall; Die lvalue-to-rvalue-Transformation in %code% operands sollte nur dann gelten, wenn der Operand genau den korrekten Rückgabetyp hat.

Außerdem scheinen GCC und Clang in diesem Bereich ein verwirrendes und möglicherweise fehlerhaftes Verhalten zu haben. Den obigen Code auf Wandbox versuchen, sehe ich diese Ausgaben:

%Vor%

Also begann das als Werkzeugfrage und endete mit einer Nebenordnung von "Was ist das korrekte Verhalten für einen C ++ - Compiler?"

Meine Tooling-Frage lautet: In unserer Codebasis gibt es mehrere Orte, an denen %code% steht, die aber versehentlich eine Kopie anstelle einer Bewegung erzeugen, weil unsere Toolchain GCC 4.9.x und / oder Clang ist. Wir möchten diese Situation automatisch erkennen und %code% nach Bedarf einfügen. Gibt es eine einfache Möglichkeit, dieses Problem zu erkennen? Vielleicht könnten wir einen Clang-Tidy-Check oder eine %code% -Flags aktivieren?

Aber jetzt möchte ich natürlich auch wissen, was das korrekte Verhalten eines C ++ - Compilers in diesem Code ist. Zeigen diese Ausgaben GCC / Clang Fehler an? Werden sie bearbeitet? Und sollte die Sprachversion ( %code% ) eine Rolle spielen? (Ich würde denken, dass es wichtig ist, es sei denn, das korrekte Verhalten wurde über Fehlerberichte aktualisiert, die bis zu C ++ 11 zurückreichen.)

Hier ist ein vollständigerer Test , der von Barrys Antwort inspiriert wurde. Wir testen sechs verschiedene Fälle, in denen eine Umwandlung von lval zu rval wünschenswert wäre.

%Vor%

Nach Barrys Antwort scheint mir Clang 3.9+ in allen Fällen das technisch korrekte zu tun; GCC 8+ macht die wünschenswerte Sache in allen Fällen; und im Allgemeinen sollte ich aufhören zu lehren, dass Leute "nur %code% und lassen Sie den Compiler DTRT" (oder lehren Sie es zumindest mit einem großen blinkenden Vorbehalt), weil in der Praxis der Compiler nicht DTRT, wenn Sie nicht verwenden einen hochmodernen (und technisch nichtkonformen) GCC.

    
___
1
Antwort

C ++ 14 automatisch erkennen "return sollte std :: move" Situation verwenden

Mein Verständnis ist, dass in C ++ 17 das folgende Snippet das Richtige tun soll: %Vor% Das heißt, in C ++ 17 soll der Compiler sowohl d1 als auch d2 als rvalues ​​für die Zwecke der Überladungsauflösung in diesen beiden return-Anweisu...
11.02.2018, 02:47