Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How expensive is to copy an std::function?

While std::function is movable, in some cases it's not possible or not convenient. Is there a significant penalty for copying it?

Does it possibly depend on the size of the captured variables (if it was created using a lambda expression)? Is it implementation dependent?

like image 721
Petr Avatar asked Jun 06 '17 11:06

Petr


2 Answers

std::function is typically implemented as a value-semantics, small-buffer optimized, virtual-dispatch, type-erasing class.

This means if your state is small, a copy will involve no heap allocation (other than within the copy ctor of the state) and some indirection (to find how to copy this particular state).

If your state is large (larger than two std::strings on current MSVC, for example), it requires an additional heap allocation to store the state.

This is not something you want to do on a per-pixel per-frame basis, but it isn't insanely expensive.

How your particular compiler and library version implements std::function could vary, but I am unaware of any that differs significantly from the above.

So, in the following code:

std::function<std::string()> f = [s = "hello"s]{ return s; };

copying f will involve 0 heap allocations on MSVC.

Whereas, this code:

std::function<std::string()> g = [a = "a"s, b = "b"s, c = "c"s]{ return a+b+c; };

does require a heap allocation to copy g.

(And yes, both of these are really dumb function objects.)

There is an effective requirement that the small buffer optimization (SBO) be applied for certain cases (function pointers, member function pointers) in std::function by the fact that they are expected not to fail at allocating memory. Once you have written one SBO case, making it more general isn't hard, so most std::function implementations store small objects "inside themselves" and larger objects on the heap.

However, this threshold is not specified by the standard, and it is important for the performance cost, so if performance is really important, you'll have to profile to ensure that your implementation does it.

like image 200
Yakk - Adam Nevraumont Avatar answered Nov 12 '22 10:11

Yakk - Adam Nevraumont


It is indeed implementation-dependent. It also depends on what exactly you are storing in the std::function. It is surely not as cheap as simply copying a C-style function pointer.

The best thing would be for you to try writing the code the way you find clear and convenient, then, if it does not run quickly enough, profile it. If you need ultimate performance, you may find std::function is not suitable at all.

like image 31
John Zwinck Avatar answered Nov 12 '22 10:11

John Zwinck