C++ 使用tcp::acceptor::async\u accept的套接字指针所有权转移

C++ 使用tcp::acceptor::async\u accept的套接字指针所有权转移,c++,c++11,boost-asio,unique-ptr,C++,C++11,Boost Asio,Unique Ptr,我最近开始在一个项目中使用Boost.Asio,我想知道是否有人知道一个干净的解决方案,可以将新创建的套接字的所有权转移到tcp::acceptor::async_accept,而tcp::acceptor::async_accept又将此所有权转移到accept处理程序函数 提醒你,这不是一个不连贯的愿望,因为处理程序只需要被调用一次 我注意到我不能将std::bind()作为std::unique_ptr参数,因为std::bind()要求其参数是可复制的,这是理所当然的。不仅如此,Boos

我最近开始在一个项目中使用Boost.Asio,我想知道是否有人知道一个干净的解决方案,可以将新创建的套接字的所有权转移到tcp::acceptor::async_accept,而tcp::acceptor::async_accept又将此所有权转移到accept处理程序函数

提醒你,这不是一个不连贯的愿望,因为处理程序只需要被调用一次

我注意到我不能将std::bind()作为std::unique_ptr参数,因为std::bind()要求其参数是可复制的,这是理所当然的。不仅如此,Boost的AcceptHandler概念还需要可复制

因此,我的选择是:

  • 使用复制构造函数使用不推荐的std::auto_ptr方式移动对象,这可能会在新版本的Boost.Asio上造成模糊的bug
  • 使用std::shared_ptr,一旦不再需要共享所有权,即当它到达实际的处理函数时,就无法将其从指针上移除(据我所知,这是在示例上完成工作的方式)

  • 你有更好的主意给我

我在这里几乎不知所措。有人能给我一些启发吗?

我试图用c++0x标准库找到一种方法来实现这一点,但没有找到。 最终,我决定编写自己的rvalue\u reference\u包装器和rvalue\u ref()便利类。与std::bind一样,您需要将不可复制的对象包装在可复制的东西中(reference_wrapper是最好的例子)。您也可以只传递一个指针,但这意味着要更改接口

这在我的机器上起作用:

#include <iostream>
#include <functional>
#include <memory>

template< class T >
struct rvalue_reference_wrapper
{
    rvalue_reference_wrapper( T&& t )
        : t_(std::move(t))
    {}

    operator T&&() const volatile
    {
        return std::move(t_);
    }

private:
    T&& t_; 
};

template< class T >
rvalue_reference_wrapper<T> rvalue_ref( T&& t )
{
    return rvalue_reference_wrapper<T>(std::move(t));
}

void go( std::unique_ptr<int> i )
{
    std::cout << *i << std::endl;
}

int main()
{
    std::unique_ptr<int> i(new int(1));

    auto b = std::bind( go, rvalue_ref(std::move(i)) );
    //auto b = std::bind( go, std::ref(std::move(i)) ); // Wont work

    b();
}
#包括
#包括
#包括
模板
结构右值\u引用\u包装器
{
右值\u引用\u包装(T&T)
:t_(标准::移动(t))
{}
运算符T&()常量volatile
{
返回std::移动(t_);
}
私人:
T&T;
};
模板
右值参考包装右值参考(T&T)
{
返回右值引用包装(std::move(t));
}
无效go(标准::唯一的ptr i)
{

std::cout这个问题也有点相关,您可能会在boost用户的邮件列表中找到更多熟悉boost asio的人:您的解决方案很有趣,但我认为它不安全。如果从未调用
b
,指针将永远不会被释放(因为
I
不再拥有所有权,因为您已经
std::移动了它)。我错了吗?std::move()操作本身不做任何事情,它只强制转换到右值引用。直到右值被实际接受并用于修改源对象,才会有任何更改。在大多数情况下,这意味着调用移动构造函数或移动赋值操作符,这将“销毁”以安全的方式创建源对象。如果您从未使用过右值引用,左值将正常工作。这可能会导致挂起引用(左值引用和std::ref()也存在这一问题),因为这会导致挂起引用,我指的是这个建议的解决方案,例如,如果b的寿命比i长(通过从函数返回或复制到某个地方)。现在我考虑一下,对于您的用例,您将看到一个自调用“b”以来一直悬而未决的引用在离开局部作用域之前,实际上不会生成。同样,这不是右值引用包装器直接的问题,而只是您的用例,在类似的场景中,std::ref()也会出现这种情况。