Якщо ви хочете продуктивність, передавайте цінність, якщо ви зберігаєте її.
Припустимо, у вас є функція під назвою "запустити це в потоці інтерфейсу".
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), ми змушені копіювати .movestd::functionstd::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.