【问题标题】:Visual Studio 2013 C++ - Passing std::unique_ptr to a bound functionVisual Studio 2013 C++ - 将 std::unique_ptr 传递给绑定函数
【发布时间】:2013-10-18 23:30:53
【问题描述】:

使用 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&amp;,它确实在 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 签名的情况下解决这个问题?

谢谢!

【问题讨论】:

  • 你不能按值传递 unique_ptr,它没有复制构造函数。
  • 因此std::move()。如果我直接调用func(std::move(ptr)),调用它会非常好,但在绑定时就不行。
  • 那为什么不将func改为接受unique_ptr&lt;T&gt;&amp;&amp;
  • 因为它不能在 VS2013 中编译...在这种情况下,将参数设置为 std::unique_ptr&lt;T&gt;std::unique_ptr&lt;T&gt;&amp;&amp; 没有任何实际区别。

标签: c++ visual-studio c++11 visual-studio-2013


【解决方案1】:

我最近在 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)); };

【讨论】:

  • 啊,这正是我需要的!对于 Linux 目标,ifdef 也应该很容易。非常感谢!
  • 您刚刚为我节省了重新设计的工作量。谢谢。我知道 GCC 4.7 也能正确处理占位符。
  • 在 VS 2013 (VC12) 中不再需要使用假捕获值的 hack。
【解决方案2】:

您还必须将参数移动到对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)中编译的。

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 对于将参数绑定到std::function 的函数可能是这样,但我尝试使用的std::function 只有占位符。我的第一个代码 sn-p 在 GCC 中编译,但不是 VS。我正在尝试找到一种解决方法,这样我就可以保留func 的签名并仍然使用 VS 进行编译。
    猜你喜欢
    • 2015-09-03
    • 2013-01-16
    • 1970-01-01
    • 2012-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-31
    • 2021-09-25
    相关资源
    最近更新 更多