Reputation:
Using Visual Studio 2013 RC and C++, I'm trying to pass an std::unique_ptr
to a function that has been bound using std::bind
. However, I'm having trouble because VS doesn't seem to like it when I try this. Here's what I'm trying to compile:
#include <memory>
#include <iostream>
#include <functional>
void func(std::unique_ptr<int> arg)
{
std::cout << *arg << std::endl;
}
int main()
{
std::function<void (std::unique_ptr<int>)> bound =
std::bind(&func, std::placeholders::_1);
std::unique_ptr<int> ptr(new int(42));
bound(std::move(ptr));
return 0;
}
This compiles in GCC 4.8.1, but not in VS2013 RC. I've always had problems with move semantics in VS, but I'd really like to use std::unique_ptr
instead of std::shared_ptr
or raw pointers.
One workaround I've found is to change the function signature to accept an std::unique_ptr&
, which does compile in VS and GCC, but doesn't make the intent of func
taking ownership of the std::unique_ptr
particularly clear, and also prevents me from safely asynchronously calling the function unless I do something particularly ugly:
#include <memory>
#include <iostream>
#include <functional>
#include <future>
#include <string>
void func(std::unique_ptr<int>& arg)
{
std::cout << *arg << std::endl;
}
int main()
{
std::function<void (std::unique_ptr<int>&)> bound =
std::bind(&func, std::placeholders::_1);
std::unique_ptr<int> ptr(new int(42));
std::promise<void> prom;
std::async(
[&bound, &ptr, &prom]
{
std::unique_ptr<int> movedPtr = std::move(ptr);
prom.set_value();
bound(std::move(movedPtr));
});
prom.get_future().wait();
// Wait here
std::string dummy;
std::cin >> dummy;
}
Is there a way to get around this without changing func
's signature?
Thanks!
Upvotes: 4
Views: 2372
Reputation: 7339
You have to move the parameter into the bound call to func
also. Not only in the invocation of bound
bound(std::move(ptr));
but also in the binding:
std::function<void(std::unique_ptr<int>)> bound =
std::bind(func,
std::bind(std::move<std::unique_ptr<int>&>,
std::placeholders::_1));
This is compiling in VS2013 (update 4) for me.
Upvotes: 1
Reputation: 1369
I had the same problem with VS 2012 recently. I believe this is a bug in MSVC; at least in MSVC++11 the pseudo-variadic expansion seems to forward the parameters by value to some internal function. Seems this hasn't been improved.
As a workaround, I'm using lambdas instead, but another hack is required to make it work:
std::function<void (std::unique_ptr<int>)> bound =
[] (std::unique_ptr<int> arg) { func(std::move(arg)); };
still doesn't compile. But if you add any captured value (even one that isn't used), it compiles:
int x;
std::function<void (std::unique_ptr<int>)> bound =
[x] (std::unique_ptr<int> arg) { func(std::move(arg)); };
Upvotes: 2
Reputation: 3832
Functions bound with std::bind
do not forward arguments, it copies them to the function. As a result, std::bind
doesn't work with move-only types as of c++11. This problem is the idea behind proposals for "more perfect forwarding" (like this one). There's a newer one, but I can't seem to find it right now.
Upvotes: 0