My code:
#include <iostream>
#include <functional>
using namespace std;
struct A {
A() = default;
A(const A&) {
cout << "copied A" << endl;
}
};
void foo(A a) {}
int main(int argc, const char * argv[]) {
std::function<void(A)> f = &foo;
A a;
f(a);
return 0;
}
I'm seeing "copied A" twice on the console. Why is the object being copied twice, not once? How can I prevent this properly?
It's being copied because you pass it by value. You could avoid all copies by passing it as a const reference instead.
The specialization
std::function<R(Args...)>
has a call operator with the following declaration:In your case, this means that the operator takes
A
. As such, callingf(a)
results in a copy due to the pass-by-value semantics. However, the underlyingfoo
target also accepts its argument by value. Thus there will be a second copy when the parameter tof
is forwarded tofoo
.This is by design, and in fact if
A
had a move constructor there would be only one copy followed by a move construction -- and callingf(std::move(a))
would only result in two move constructions. If you feel that two copies are too much you need to reconsider whether bothfoo
andf
should takeA
instead of e.g.A const&
, and/or whetherA
can have a sensible move constructor.You can also do
std::function<void(A const&)> f = &foo;
without modifyingfoo
. But you should reserve that for the case where modifyingfoo
is beyond your control, and/or makingA
cheaply move constructible is not an option. There is nothing wrong with passing by value in C++11, so I suggest that either both should takeA
, or both should takeA const&
.