4

使用 Visual Studio 2013 RC 和 C++,我试图将一个传递std::unique_ptr给已使用std::bind. 但是,我遇到了麻烦,因为当我尝试这个时,VS 似乎不喜欢它。这是我要编译的内容:

#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;
}

这可以在 GCC 4.8.1 中编译,但不能在 VS2013 RC 中编译。我一直在 VS 中遇到移动语义问题,但我真的很想使用std::unique_ptr而不是std::shared_ptr或原始指针。

我发现的一种解决方法是将函数签名更改为接受std::unique_ptr&,它确实在 VS 和 GCC 中编译,但并没有使func获取所有权的意图std::unique_ptr特别清楚,并且还阻止我安全地异步调用该函数,除非我做了一些特别丑陋的事情:

#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;
}

有没有办法在不改变func签名的情况下解决这个问题?

谢谢!

4

3 回答 3

2

我最近在 VS 2012 上遇到了同样的问题。我相信这是 MSVC 中的一个错误;至少在 MSVC++11 中,伪变量扩展似乎将参数按值转发到某个内部函数。这个好像没有改善。
作为一种解决方法,我改用 lambdas,但需要另一个 hack 才能使其工作:

std::function<void (std::unique_ptr<int>)> bound =
    [] (std::unique_ptr<int> arg) { func(std::move(arg)); };

仍然没有编译。但是,如果您添加任何捕获的值(即使是未使用的值),它会编译:

int x;
std::function<void (std::unique_ptr<int>)> bound =
    [x] (std::unique_ptr<int> arg) { func(std::move(arg)); };
于 2013-10-11T11:37:01.727 回答
1

您还必须将参数移动到绑定调用中func。不仅在调用bound

bound(std::move(ptr));

而且在绑定中:

std::function<void(std::unique_ptr<int>)> bound =
    std::bind(func,
              std::bind(std::move<std::unique_ptr<int>&>,
                        std::placeholders::_1));

这是为我在 VS2013(更新 4)中编译的。

于 2015-02-13T21:33:33.553 回答
0

绑定的函数std::bind不转发参数,它会将它们复制到函数中。因此,std::bind从 c++11 开始,它不适用于仅移动类型。这个问题是“更完美的转发”提案背后的想法(比如这个)。有一个较新的,但我现在似乎找不到它。

于 2013-10-11T01:49:16.707 回答