I have an API which just enters a subscription into a vector of callbacks. The vector uses std::function which could be partially heap allocated, hence move operations on std::function make sense. Now I could implement this API in two ways:
- Take by value
- Take by rvalue reference
The chances that the user just puts in a lambda (rvalue ref) are really big in this case. If I take by value it will move-construct the new function object in my function body, but I actually just want to forward it to the vector element construct. This would therefore be an unnecessary inefficiency.
On the other hand, if I take by rvalue ref, the user is forced to provide an rvalue. But what if he wants to distribute the function object to multiple sinks? Right, he just has to make the copy the object himself before the call.
Now: Why not always aim for the second design, which is, taking rvalue references and let the caller make the copy? It doesn't imply any penalties on the user, he just hast to remember to copy the object first IF he wants to move the object elsewhere as well, but other than that the user stays in full controll of how the API should behave and will never have the performance penalty associated with move-constructing the object.
#include <functional>
#include <cstdio>
#include <vector>
struct entity
{
auto on_change(std::function<void()>&& cb)
{
callbacks_.push_back(std::move(cb));
}
auto print_all() {
std::for_each(callbacks_.cbegin(), callbacks_.cend(), [](const auto cb){ cb(); });
}
std::vector<std::function<void()>> callbacks_;
};
auto foo() -> void {
printf("Hello from function!\n");
}
int main()
{
entity e,d;
// Normal case
e.on_change([](){ printf("Hello from lambda!\n"); });
// Special case
auto fn = std::function<void()>([]{ printf("Hello from function that gets distributed multiple times!\n"); });
// these two don't work
// e.on_change(fn);
// d.on_change(fn);
// But why not like this?
e.on_change(std::function<void()>(fn));
d.on_change(std::move(fn));
e.print_all();
d.print_all();
}
Output:
Hello from lambda!
Hello from function that gets distributed multiple times!
Hello from function that gets distributed multiple times!
Note: This other question deals with the differentiation of rvalue vs lvalue which is not what this question is about.