While working on this question, I noticed that GCC (v4.7)'s implementation of std::function
moves its arguments when they are taken by value. The following code shows this behavior:
#include <functional>
#include <iostream>
struct CopyableMovable
{
CopyableMovable() { std::cout << "default" << '\n'; }
CopyableMovable(CopyableMovable const &) { std::cout << "copy" << '\n'; }
CopyableMovable(CopyableMovable &&) { std::cout << "move" << '\n'; }
};
void foo(CopyableMovable cm)
{ }
int main()
{
typedef std::function<void(CopyableMovable)> byValue;
byValue fooByValue = foo;
CopyableMovable cm;
fooByValue(cm);
}
// outputs: default copy move move
We see here that a copy of cm
is performed (which seems reasonable since the byValue
's parameter is taken by value), but then there are two moves. Since function
is operating on a copy of cm
, the fact that it moves its argument can be seen as an unimportant implementation detail. However, this behavior causes some trouble when using function
together with bind
:
#include <functional>
#include <iostream>
struct MoveTracker
{
bool hasBeenMovedFrom;
MoveTracker()
: hasBeenMovedFrom(false)
{}
MoveTracker(MoveTracker const &)
: hasBeenMovedFrom(false)
{}
MoveTracker(MoveTracker && other)
: hasBeenMovedFrom(false)
{
if (other.hasBeenMovedFrom)
{
std::cout << "already moved!" << '\n';
}
else
{
other.hasBeenMovedFrom = true;
}
}
};
void foo(MoveTracker, MoveTracker) {}
int main()
{
using namespace std::placeholders;
std::function<void(MoveTracker)> func = std::bind(foo, _1, _1);
MoveTracker obj;
func(obj); // prints "already moved!"
}
Is this behavior allowed by the standard? Is std::function
allowed to move its arguments? And if so, is it normal that we can convert the wrapper returned by bind
into a std::function
with by-value parameters, even though this triggers unexpected behavior when dealing with multiple occurrences of placeholders?
std::function
. Namely, the fact that when creating atie
, move is used from the original argument to both expected outputs. – Anglosaxonauto
to deduce the "bind-wrapper" type, instead of usingstd::function
? – SaraisaraiyaMoveTracker&
and will be forwarded as an lvalue reference tofoo
, twice, resulting in two copy construction from those lvalue references. – Sacaton