Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I pass an std::function by const-reference?

People also ask

Should std :: function be passed by reference or value?

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& .

Is it better to pass by reference?

2) For passing large sized arguments: If an argument is large, passing by reference (or pointer) is more efficient because only an address is really passed, not the entire object.

When should you use a const parameter passed by reference?

Pass Using Const Reference in C++ Now, we can use the const reference when we do not want any memory waste and do not change the variable's value. The above code will throw a compile error as num = num +10 is passed as a const reference.

What is one benefit of declaring the parameter as const reference?

The const qualifier Forbids the code to modify the argument, so the programmer can rest assured that the source object will remain unchanged. The argument is passed as a reference, so the Function receives a copy that can be modified without affecting the original variable.


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 moved 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 moved 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.


If you're worried about performance, and you aren't defining a virtual member function, then you most likely should not be using std::function at all.

Making the functor type a template parameter permits greater optimization than std::function, including inlining the functor logic. The effect of these optimizations is likely to greatly outweigh the copy-vs-indirection concerns about how to pass std::function.

Faster:

template<typename Functor>
void callFunction(Functor&& x)
{
    x();
}

As usual in C++11, passing by value/reference/const-reference depends on what you do with your argument. std::function is no different.

Passing by value allows you to move the argument into a variable (typically a member variable of a class):

struct Foo {
    Foo(Object o) : m_o(std::move(o)) {}

    Object m_o;
};

When you know your function will move its argument, this is the best solution, this way your users can control how they call your function:

Foo f1{Object()};               // move the temporary, followed by a move in the constructor
Foo f2{some_object};            // copy the object, followed by a move in the constructor
Foo f3{std::move(some_object)}; // move the object, followed by a move in the constructor

I believe you already know the semantics of (non)const-references so I won't belabor the point. If you need me to add more explanations about this, just ask and I'll update.