I was working with boost::bind (Boost 1.64.0 and gcc 8.3.0) to create a callable object and noticed an interesting feature An object passed in bind constructor as an argument to a wrappable function is copied multiple times. Even if the object is wrapped in std::move(). Although std::bind works as expected. Example:
#include <iostream>
#include <boost/bind.hpp>
#include <functional>
class Test
{
public:
Test()
{
std::cout << "Create\n";
}
Test(const Test& rhs)
{
std::cout << "Copy\n";
}
Test(Test&& rhs)
{
std::cout << "Move\n";
}
~Test() noexcept
{
}
};
void foo(Test& t)
{
}
int main()
{
Test t;
auto f = boost::bind(&foo, t);
f();
}
Output for boost::bind(&foo, t);
Create
Copy
Copy
Copy
Copy
Copy
Output for boost::bind(&foo, std::move(t));
Create
Move
Copy
Copy
Copy
Copy
Output for std::bind(&foo, t);
Create
Copy
Output for std::bind(&foo, std::move(t));
Create
Move
Thank you!
That's by design.
To avoid it, avoid copies of the bind adaptor and use ref
:
auto f = boost::bind(&foo, boost::ref(t));
Mostly due to the fact that your constructor cannot be elided. Keep it an aggregate or trivial constructor and it doesn't happen.
Yes, bind captures arguments by value (unless you use explicit ref()
or cref()
to create reference_wrapper
s.)
#include <boost/bind.hpp>
#include <functional>
#include <iostream>
struct Test {
Test() { std::cout << "Create\n"; }
Test(const Test& /*unused*/) { std::cout << "Copy\n"; }
Test(Test&& /*unused*/) { std::cout << "Move\n"; }
~Test() noexcept { }
};
void foo(Test& /*unused*/) {}
int main() {
Test t;
auto f = boost::bind(&foo, boost::ref(t));
f();
}
Prints:
Create