Jeśli chcesz osiągnąć wydajność, podaj wartość, jeśli ją przechowujesz.
Załóżmy, że masz funkcję o nazwie "uruchom to w wątku UI".
std::future<void> run_in_ui_thread(std::function<void()>)
który działa kod, w „Ul” wątek, a następnie sygnalizuje future
po zakończeniu. (Przydatne w ramach UI gdzie wątek UI jest, gdy ci mają bałagan z elementów UI)
Mamy dwa podpisy Rozważamy:
std::future<void> run_in_ui_thread(std::function<void()>) // (A)
std::future<void> run_in_ui_thread(std::function<void()> const&) // (B)
Teraz mogą z nich korzystać w sposób następujący:
run_in_ui_thread([=]{
// code goes here
}).wait();
który tworzy anonimowego zamknięcie (lambda) skonstruować std::function
z niego, przekazać go do funkcji run_in_ui_thread
, a następnie czekać na zakończenie pracy w głównym wątku.
W przypadku (A), std::function
jest bezpośrednio skonstruowany z naszej lambda, która jest następnie używana w ramach run_in_ui_thread
. Wartość lambda to move
d do std::function
, więc każdy ruchomy stan jest skutecznie przenoszony do niej.
W drugim przypadku, tymczasowy std::function
jego tworzenia, lambda move
d do niego, to tymczasowa std::function
jest stosowany jako odniesienie w run_in_ui_thread
.
Jak dotąd, tak dobrze - obaj wykonują identycznie. Z wyjątkiem run_in_ui_thread
zrobi kopię swojego argumentu funkcji do wysłania do wątku interfejsu użytkownika do wykonania! (powróci, zanim zostanie zrobione, więc nie może po prostu użyć odniesienia do niego). Dla przypadku (A), po prostu move
z std::function
do jego długoterminowego przechowywania. W przypadku (B) jesteśmy zmuszeni skopiować std::function
.
Ten sklep sprawia, że przekazywanie według wartości jest bardziej optymalne. Jeśli istnieje możliwość zapisania kopii pliku std::function
, podaj wartość. W przeciwnym razie, każda z nich jest mniej więcej równoważna: jedyną wadą wartości dodanej jest to, że używasz tego samego nieporęcznego obiektu std::function
i używasz jednej metody podrzędnej za drugą. Poza tym, move
będzie tak wydajny jak const&
.
Teraz są pewne inne różnice między tymi dwoma, które najczęściej wskakują, jeśli mamy stały stan w ramach std::function
.
Załóżmy, że std::function
przechowuje jakiś obiekt z operator() const
, ale ma również pewne elementy danych, które modyfikuje (jakże nieuprzejmość!).
W przypadku std::function<> const&
zmodyfikowane zmienne danych mutable
będą propagować poza wywołaniem funkcji. W przypadku std::function<>
nie będą.
To stosunkowo dziwny przypadek narożny.
Chcesz traktować std::function
tak jak każdy inny potencjalnie ciężki, tani, przenośny. Przenoszenie jest tanie, kopiowanie może być kosztowne.
Prawdopodobnie nie. Nie wiem na pewno, ale spodziewałbym się, że 'sizeof (std :: function)' będzie nie większy niż '2 * sizeof (size_t)', który jest najmniejszym rozmiarem, jaki kiedykolwiek rozważałeś dla odniesienia do const . –
@Mats: Nie sądzę, że rozmiar 'std :: function' wrapper jest tak samo ważny jak złożoność kopiowania. W przypadku kopii głębokich może to być znacznie droższe niż sugeruje 'sizeof'. –
Czy należy "przenieść" tę funkcję? – Yakk