Warum hat make_unique eine zusätzliche Bewegung mit einem Konstruktor, der std :: bind als Argument annehmen kann?

8

Ich habe eine triviale Klasse mit einem Konstruktor, der wie folgt aussieht:

%Vor%

Der Konstruktor kann mit std :: bind:

verwendet werden %Vor%

Wenn Sie es in der oben beschriebenen Weise verwenden, erhalten Sie eine Kopie von "Ding" und dann eine Konstruktionsänderung für diese Kopie.

Allerdings Folgendes tun:

%Vor%

Ergebnisse in zwei Move-Konstruktionen. Meine Fragen sind:

  • Wenn genau, ist der Move-Konstruktor für 'Sache'
  • Warum wird es zweimal mit make_unique aufgerufen?

Hier ist das minimale Beispiel:

%Vor%

Mit Ausgabe:

%Vor%

PS: Ich habe diese Frage sowohl mit C ++ 11 als auch mit 14 markiert, da das gleiche Problem auftritt, wenn das C ++ 11 Flag an gcc mit der häufig verwendeten make_unique Funktion übergeben wird (make_unique und perfekte Weiterleitung )

    
Prismatic 14.01.2015, 21:22
quelle

1 Antwort

9

Ich denke, dass die zusätzliche Bewegung bei Verwendung von make_unique auf Verschiebung von Elision in Event(std::bind(lambda,thing)) zurückzuführen ist.

Der Konstruktor von Event , der aufgerufen wird, ist Event(function<void()> && f) , daher muss ein temporäres function<void()> erstellt werden. Dieses temporäre Objekt wird mit dem Rückgabewert des std::bind -Ausdrucks initialisiert.

Der Konstruktor, der diese Konvertierung vom Rückgabetyp std::bind nach std::function<void()> durchführt, verwendet das Argument als Wert :

%Vor%

Das bedeutet, dass wir den Rückgabewert von std::bind auf diesen Parameter f des Konstruktors von function<void()> verschieben müssen. Aber diese Bewegung ist geeignet für move elision .

Wenn wir dieses temporär über make_unique übergeben, wurde es an eine Referenz gebunden und die Verschiebung kann nicht mehr angewendet werden. Wenn wir daher die Bewegung Elision unterdrücken:

%Vor%

(Wir können std::move als Implementierung von suppress_elision verwenden.)

Wir können die gleiche Anzahl von Zügen beobachten: Live-Beispiel

Erklärung des gesamten Vorgangs:

Für new Event(std::bind(lambda,thing)) :

%Vor%

(*) kann gelöscht werden (+) aber nicht, wahrscheinlich weil das interne Funktionsobjekt auf dem Heap ist und nur ein Zeiger bewegt wird. Überprüfen Sie, indem Sie m_f(std::move(f)) durch m_f() ersetzen.

Für make_unique<Event>(std::bind(lambda,thing)) :

%Vor%     
dyp 14.01.2015, 22:19
quelle

Tags und Links