Якщо ви хочете продуктивність, передавайте цінність, якщо ви зберігаєте її.
Припустимо, у вас є функція під назвою "запустити це в потоці інтерфейсу".
std::future<void> run_in_ui_thread( std::function<void()> )
який виконує деякий код у потоці "ui", а потім сигналізує про future
завершення. (Корисно в структурах інтерфейсу користувача, де потік користувальницького інтерфейсу знаходиться там, де ви повинні поплутатися з елементами інтерфейсу)
Ми маємо два підписи, які ми розглядаємо:
std::future<void> run_in_ui_thread( std::function<void()> ) // (A)
std::future<void> run_in_ui_thread( std::function<void()> const& ) // (B)
Тепер ми, ймовірно, використовуватимемо наступне:
run_in_ui_thread( [=]{
// code goes here
} ).wait();
який створить анонімне закриття (лямбда), побудує std::function
з нього, передасть його run_in_ui_thread
функції, а потім дочекайтеся її завершення в основному потоці.
У випадку (A), std::function
безпосередньо побудований з нашої лямбда, який потім використовується в межах run_in_ui_thread
. Лямбда move
перетворюється на std::function
, тому будь-який рухливий стан ефективно переноситься в неї.
У другому випадку створюється тимчасовий std::function
, лямбда move
впадає в нього, тоді цей тимчасовий std::function
використовується за допомогою посилання в межах run_in_ui_thread
.
Поки що так добре - вони обидва виступають однаково. За винятком того run_in_ui_thread
, що збирається зробити копію свого аргументу функції, щоб надіслати потік ui для виконання! (він повернеться до того, як буде зроблено з ним, тому він не може просто використовувати посилання на нього). Для випадку (А), ми просто в його тривалого зберігання. У випадку (B), ми змушені копіювати .move
std::function
std::function
Цей магазин робить проходження по вартості більш оптимальним. Якщо є якась можливість, ви зберігаєте копію документа std::function
, передайте значення. В іншому випадку будь-який спосіб є приблизно еквівалентним: єдиний недолік побічної вартості - це якщо ви приймаєте ту саму об'ємну std::function
і маєте один під-метод за іншим. Якщо це забороняється, засіб move
буде настільки ж ефективним, як і const&
.
Зараз є деякі інші відмінності між цими двома, які здебільшого спричиняють ситуацію, якщо ми маємо стійкий стан всередині країни std::function
.
Припустимо, що std::function
зберігає якийсь об’єкт з a operator() const
, але він також має деякі mutable
члени даних, які він модифікує (як грубо!).
У std::function<> const&
випадку, коли mutable
модифіковані члени даних поширюватимуться з виклику функції. У std::function<>
випадку вони не стануть.
Це відносно дивний кутовий випадок.
Ви хочете поводитись так, std::function
як до будь-якого іншого, можливо важкого, дешевого рухомого типу. Переміщення дешеве, копіювання може бути дорогим.
sizeof(std::function)
що це не більше2 * sizeof(size_t)
, що є найменшим розміром, який ви коли-небудь вважали б для посилання на const.