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:
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 )
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 :
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:
(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))
:
(*) 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))
: