If you want performance, pass by value if you are storing it.
Suppose you have a function called "run this in the UI thread".
std::future<void> run_in_ui_thread( std::function<void()> )
which runs some code in the "ui" thread, then signals the future
when done. (Useful in UI frameworks where the UI thread is where you are supposed to mess with UI elements)
We have two signatures we are considering:
std::future<void> run_in_ui_thread( std::function<void()> ) // (A)
std::future<void> run_in_ui_thread( std::function<void()> const& ) // (B)
Now, we are likely to use these as follows:
run_in_ui_thread( [=]{
// code goes here
} ).wait();
which will create an anonymous closure (a lambda), construct a std::function
out of it, pass it to the run_in_ui_thread
function, then wait for it to finish running in the main thread.
In case (A), the std::function
is directly constructed from our lambda, which is then used within the run_in_ui_thread
. The lambda is move
d into the std::function
, so any movable state is efficiently carried into it.
In the second case, a temporary std::function
is created, the lambda is move
d into it, then that temporary std::function
is used by reference within the run_in_ui_thread
.
So far, so good -- the two of them perform identically. Except the run_in_ui_thread
is going to make a copy of its function argument to send to the ui thread to execute! (it will return before it is done with it, so it cannot just use a reference to it). For case (A), we simply move
the std::function
into its long-term storage. In case (B), we are forced to copy the std::function
.
That store makes passing by value more optimal. If there is any possibility you are storing a copy of the std::function
, pass by value. Otherwise, either way is roughly equivalent: the only downside to by-value is if you are taking the same bulky std::function
and having one sub method after another use it. Barring that, a move
will be as efficient as a const&
.
Now, there are some other differences between the two that mostly kick in if we have persistent state within the std::function
.
Assume that the std::function
stores some object with a operator() const
, but it also has some mutable
data members which it modifies (how rude!).
In the std::function<> const&
case, the mutable
data members modified will propagate out of the function call. In the std::function<>
case, they won't.
This is a relatively strange corner case.
You want to treat std::function
like you would any other possibly heavy-weight, cheaply movable type. Moving is cheap, copying can be expensive.