Если вы хотите производительность, передайте по значению, если вы храните его.
Предположим, у вас есть функция «запустить это в потоке пользовательского интерфейса».
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что собирается сделать копию своего аргумента функции для отправки в поток пользовательского интерфейса для выполнения! (он вернется до того, как с ним будет покончено, поэтому он не может просто использовать ссылку на него). Для случая (А), мы просто в его длительного хранения. В случае (B) мы вынуждены копировать .movestd::functionstd::function
Этот магазин делает переход по стоимости более оптимальным. Если есть вероятность, что вы храните копию std::function, передайте по значению. В противном случае, любой из этих способов примерно эквивалентен: единственным недостатком по значению является то, что вы берете один std::functionи тот же громоздкий и используете его один вспомогательный метод за другим. За исключением этого, a moveбудет столь же эффективным, как и const&.
Теперь есть некоторые другие различия между двумя, которые в основном включаются, если у нас есть постоянное состояние внутри std::function.
Предположим, что std::functionхранит некоторый объект с operator() const, но у него также есть некоторые mutableчлены данных, которые он изменяет (как грубо!).
В этом std::function<> const&случае mutableизмененные члены-данные будут распространяться из вызова функции. В std::function<>случае, они не будут.
Это довольно странный угловой случай.
Вы хотите относиться так же, std::functionкак и к любому другому, возможно, тяжелому, дешевому подвижному типу. Перемещение это дешево, копирование может быть дорого.
sizeof(std::function)это будет не более чем2 * sizeof(size_t), что является наименьшим размером, который вы когда-либо рассматривали бы для константной ссылки.