Jeśli chcesz wydajności, podaj wartość, jeśli ją przechowujesz.
Załóżmy, że masz funkcję o nazwie „uruchom to w wątku interfejsu użytkownika”.
std::future<void> run_in_ui_thread( std::function<void()> )
który uruchamia kod w wątku „ui”, a następnie sygnalizuje zakończenie future
. (Przydatne w strukturach UI, w których wątek UI jest miejscem, w którym powinieneś zadzierać z elementami UI)
Rozważamy dwa podpisy:
std::future<void> run_in_ui_thread( std::function<void()> ) // (A)
std::future<void> run_in_ui_thread( std::function<void()> const& ) // (B)
Teraz prawdopodobnie użyjemy ich w następujący sposób:
run_in_ui_thread( [=]{
// code goes here
} ).wait();
co utworzy anonimowe zamknięcie (lambda), skonstruuje z niego std::function
wyjście, przekaże je do run_in_ui_thread
funkcji, a następnie zaczeka, aż zakończy się działanie w głównym wątku.
W przypadku (A), std::function
jest on konstruowany bezpośrednio z naszej lambdy, która jest następnie używana w run_in_ui_thread
. Lambda jest move
d do std::function
, więc każdy ruchomy stan jest skutecznie przenoszony do niej.
W drugim przypadku std::function
tworzony jest tymczasowy , lambda jest move
w nim d, a następnie ten tymczasowy std::function
jest używany przez odniesienie w run_in_ui_thread
.
Jak na razie dobrze - obaj grają identycznie. Tyle run_in_ui_thread
że program utworzy kopię swojego argumentu funkcji do wysłania do wątku interfejsu użytkownika w celu wykonania! (wróci, zanim zostanie z nim zakończony, więc nie może po prostu użyć odniesienia do niego). W przypadku (A), po prostu do jego długotrwałego przechowywania. W przypadku (B) jesteśmy zmuszeni skopiować plik .move
std::function
std::function
Ten sklep sprawia, że przekazywanie wartości jest bardziej optymalne. Jeśli istnieje możliwość, że przechowujesz kopię pliku std::function
, podaj wartość. W przeciwnym razie obie metody są z grubsza równoważne: jedyną wadą wartości bocznej jest to, że bierzesz tę samą masę std::function
i jedną metodę podrzędną po drugiej. Poza tym, a move
będzie tak samo wydajne jak const&
.
Teraz są pewne inne różnice między tymi dwoma, które najczęściej pojawiają się, jeśli mamy trwały stan w obrębie std::function
.
Załóżmy, że std::function
przechowuje jakiś obiekt z a operator() const
, ale ma też kilka mutable
członków danych, które modyfikuje (jakie niegrzeczne!).
W takim std::function<> const&
przypadku mutable
zmodyfikowane elementy składowe danych będą propagowane poza wywołanie funkcji. W takim std::function<>
przypadku nie będą.
To stosunkowo dziwny przypadek narożny.
Chcesz traktować std::function
jak każdy inny potencjalnie ciężki, tani przenośny typ. Przenoszenie jest tanie, kopiowanie może być kosztowne.
sizeof(std::function)
się, że nie będzie więcej niż2 * sizeof(size_t)
, czyli najmniejszy rozmiar, jaki kiedykolwiek wziąłbyś pod uwagę jako odniesienie do stałej.