Brauche Hilfe beim Verstehen von C ++ 11 Move Constructors [duplicate]

8

Als C ++ Neuling habe ich wirklich Probleme, den neuen Move-Constructor von C ++ 11 zu verstehen und ich hoffe, dass jemand eine bestimmte Situation erklären kann, über die ich gestolpert bin. Nehmen wir diesen Beispielcode:

%Vor%

Also habe ich eine createModel -Funktion erstellt, die ein Modell als temporären rvalue zurückgeben soll und ich möchte es einem lvalue zuweisen. Ich möchte nicht, dass der Compiler Kopien des Model -Objekts erstellt, also definiere ich den Kopierkonstruktor als privat und mache dasselbe mit dem Zuweisungsoperator, um sicherzustellen, dass keine Daten kopiert werden. Danach kompiliert der Code nicht mehr korrekt, also habe ich den Move-Konstruktor hinzugefügt und jetzt kompiliert. Aber wenn ich das Programm starte, bekomme ich diese Ausgabe:

%Vor%

Also wurde der Move Constructor nie aufgerufen. Ich verstehe nicht, warum ich den Move-Konstruktor angeben muss, um das Programm kompilieren zu können, wenn es während der Laufzeit überhaupt nicht benutzt wird.

Liegt das daran, dass der Compiler (GCC 4.8.2) den Move Constructor entfernt hat? Oder wird hier eine andere Magie ausgeführt?

Kann jemand bitte erklären, was genau im obigen Code passiert? Der Code tut, was ich will, aber ich verstehe wirklich nicht warum.

    
kayahr 13.07.2014, 11:21
quelle

3 Antworten

7

Es gibt zwei Moves, die in Ihrem Programm passieren können:

  1. Von der Funktion zum Rückgabeobjekt.
  2. Vom Rückgabeobjekt zu model .

Diese beiden Bewegungen können vom Compiler aus dem gleichen Grund weggelassen werden:

  

Wenn ein temporäres Klassenobjekt, das nicht an einen Verweis (12.2) gebunden wurde, in ein Klassenobjekt mit demselben cv-unqualifizierten Typ kopiert / verschoben wird, kann der Kopier- / Verschiebevorgang durch direktes Konstruieren des temporären Objekts weggelassen werden in das Ziel der ausgelassenen Kopie / move

Es gibt andere Situationen, in denen die Kopie / Bewegung Elision auftritt (siehe § 12.8 / 31 in C ++ 11). Beachten Sie, dass Kopieren / Verschieben ganz optional ist - der Compiler muss das nicht tun.

Beachten Sie, dass der Compiler absolut nichts weiter optimieren darf, solange er nicht das Verhalten Ihres Programms (unter der as-if-Regel ) ändert. Der Grund dafür, dass copy / move elision im Standard explizit erwähnt wird, ist, dass das Verhalten Ihres Programms ändern kann , wenn Ihre Kopier- / Verschiebungskonstruktoren Nebenwirkungen haben. Der Compiler darf diese Optimierung auch dann durchführen, wenn er das Verhalten Ihres Programms ändert. Das ist der Grund, warum Ihre Copy / Move-Konstruktoren niemals Nebenwirkungen haben sollten , weil Ihr Programm dann mehrere gültige Ausführungspfade hat.

Sie können die Option -fno-elide-constructors an gcc übergeben, um sicherzustellen, dass diese Optimierung nie ausgeführt wird.

    
Joseph Mansfield 13.07.2014, 11:41
quelle
1

Ich denke, das ist, was Sie Kopie Elision nennen (d. h. die Kopie eines Objekts verhindern) und direkt verwenden. Siehe: elision kopieren: move constructor not Wird bei der Verwendung von Ternärausdrücken in der Return-Anweisung aufgerufen?

    
cageman 13.07.2014 11:31
quelle
1

Sie sind ein "Opfer" der Rückgabewertoptimierung hier.

Beachten Sie: "In C ++ ist es besonders bemerkenswert, dass das beobachtbare Verhalten des resultierenden Programms geändert werden darf".

BEARBEITEN: Daher kann der Compiler die Optimierung anwenden, obwohl die Nebenwirkungen von move-ctor (cout) geändert wurden.

    
namezero 13.07.2014 11:35
quelle

Tags und Links