Если вы хотите производительность, передайте по значению, если вы храните его.
Предположим, у вас есть функция «запустить это в потоке пользовательского интерфейса».
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) мы вынуждены копировать .move
std::function
std::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)
, что является наименьшим размером, который вы когда-либо рассматривали бы для константной ссылки.