13

I do not quite understand what an instance of std::function actually contains.

Is it more efficient to pass it by-value or by-reference?

What are the performance effects in the following examples?

by-value:

void printStats(std::function<void(const char *)> printer);
. . .
std::string tmp;
printStats([&tmp](const char * msg){ tmp += msg; });

by rvalue-reference:

void printStats(std::function<void(const char *)>&& printer);
. . .
std::string tmp;
printStats([&tmp](const char * msg){ tmp += msg; });
rustyx
  • 80,671
  • 25
  • 200
  • 267
  • I think the simple answer is by-value but just in case you did not know: [when to use templates over `std::function`](http://stackoverflow.com/questions/14677997/stdfunction-vs-template) – Maikel Apr 01 '16 at 12:02
  • Copying a `std::function` generally requires a dynamic memory allocation, is therefore somewhat expensive and should therefore be passed by reference. – nwp Apr 01 '16 at 12:05
  • related: [Should I pass an std::function by const-reference?](https://stackoverflow.com/questions/18365532/should-i-pass-an-stdfunction-by-const-reference) – Alexander Malakhov Feb 07 '18 at 11:26

1 Answers1

8

First, std::function is required to avoid allocation in the case where the target is a function pointer of std::reference_wrapper; implementations are encouraged to avoid allocation for "small" targets:

[...] for example, where f's target is an object holding only a pointer or reference to an object and a member function pointer.

That means that copying a std::function whose target is large will involve an allocation and a copy of the target (reference counting is not permitted, since the target might have mutable state). However, in your specific case the copy will be elided since you are calling your function with a prvalue temporary.

In your specific case, since you are calling the function immediately you don't need to worry about taking ownership of it, so it would be better to take the function by const reference. Taking it by rvalue reference would cause a headache to a user who has an existing lvalue or const reference to a function; they would need to std::move it (in the former case) or create a prvalue temporary copy (in the latter case).

ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • 1
    "Encouraged" is not the same as "required". Further, that quoted text is in a **note**, and notes are not normative. – Pete Becker Apr 01 '16 at 13:09