Wenn Sie Leistung wünschen, übergeben Sie den Wert, wenn Sie ihn speichern.
Angenommen, Sie haben eine Funktion namens "Führen Sie dies im UI-Thread aus".
std::future<void> run_in_ui_thread( std::function<void()> )
Das führt einen Code im "UI" -Thread aus und signalisiert dann, future
wann fertig. (Nützlich in UI-Frameworks, in denen sich der UI-Thread dort befindet, wo Sie mit UI-Elementen herumspielen sollen.)
Wir haben zwei Unterschriften, die wir in Betracht ziehen:
std::future<void> run_in_ui_thread( std::function<void()> ) // (A)
std::future<void> run_in_ui_thread( std::function<void()> const& ) // (B)
Nun werden wir diese wahrscheinlich wie folgt verwenden:
run_in_ui_thread( [=]{
// code goes here
} ).wait();
Dadurch wird ein anonymer Abschluss (ein Lambda) erstellt, ein std::function
Out daraus erstellt, an die run_in_ui_thread
Funktion übergeben und gewartet, bis die Ausführung im Hauptthread abgeschlossen ist.
In Fall (A) wird das std::function
direkt aus unserem Lambda konstruiert, das dann innerhalb des verwendet wird run_in_ui_thread
. Das Lambda wird move
in den std::function
Zustand gebracht, so dass jeder bewegliche Zustand effizient in ihn hineingetragen wird.
Im zweiten Fall wird ein Temporär std::function
erstellt, das Lambda wird darin move
eingefügt, dann dieses Temporärstd::function
als Referenz innerhalb des verwendet run_in_ui_thread
.
So weit, so gut - die beiden arbeiten identisch. Außer das run_in_ui_thread
wird eine Kopie seines Funktionsarguments erstellen, um es zur Ausführung an den UI-Thread zu senden! (Es wird zurückgegeben, bevor es damit fertig ist, daher kann es nicht einfach einen Verweis darauf verwenden.) Für Fall (A) legen wir einfach move
das std::function
in seine Langzeitlagerung. In Fall (B) sind wir gezwungen, das zu kopierenstd::function
.
Dieser Laden macht die Wertübergabe optimaler. Wenn die Möglichkeit besteht, dass Sie eine Kopie von speichern std::function
, übergeben Sie den Wert. Ansonsten ist jeder Weg ungefähr gleichwertig: Der einzige Nachteil des Nebenwerts besteht darin, dass Sie denselben sperrigen nehmen std::function
und eine Submethode nach der anderen verwenden. Ansonsten ist a move
so effizient wie a const&
.
Nun gibt es einige andere Unterschiede zwischen den beiden, die meistens auftreten, wenn wir einen anhaltenden Zustand innerhalb der haben std::function
.
Angenommen, das std::function
Objekt wird mit einem gespeichert operator() const
, es enthält jedoch auch einige mutable
Datenelemente, die geändert werden (wie unhöflich!).
In diesem std::function<> const&
Fall werden die mutable
geänderten Datenelemente aus dem Funktionsaufruf weitergegeben. In diesem std::function<>
Fall werden sie nicht.
Dies ist ein relativ seltsamer Eckfall.
Sie möchten std::function
wie jeder andere möglicherweise schwere, billig bewegliche Typ behandeln. Umzug ist billig, Kopieren kann teuer sein.
sizeof(std::function)
, dass es nicht mehr als ist2 * sizeof(size_t)
, was die kleinste Größe ist, die Sie jemals für eine konstante Referenz in Betracht ziehen würden.