Gui Prá
Gui Prá

Reputation: 5677

Socket pointer transfer of ownership with tcp::acceptor::async_accept

I've recently started using Boost.Asio in a project and would like to know whether anyone knows a clean solution to transfer ownership of a newly created socket to tcp::acceptor::async_accept, which would in turn transfer this ownership to the accept handler function.

This isn't an incoherent desire, mind you, since the handler is to be called exactly once.

I have noticed I can't std::bind() an std::unique_ptr<> as parameter, since std::bind() requires its parameters to be CopyConstructible, and rightfully so. Not only that, but Boost's AcceptHandler concept is also required to be CopyConstructible.

So my options would be:

or

I'm pretty much at a loss here. Can anyone enlighten me?

Upvotes: 4

Views: 1331

Answers (1)

mmocny
mmocny

Reputation: 8855

I tried to find a way to do this using the c++0x standard library, but could not. Eventually I settled on writing my own rvalue_reference_wrapper and rvalue_ref() convenience class. As per usual with std::bind, you need to wrap your non copyable object in something that is copyable (reference_wrapper is the best example). You could also have just passed a pointer, but that means changing your interface.

This worked on my machine:

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

I have not made the code bulletproof, but welcome some discussion about the need for an rvalue_reference_wrapper, or how to simulate one using std::reference_wrapper.

Also, for your specific case, you will likely need to write a difference version of rvalue_reference_wrapper, which holds the object by value not by rvalue reference, since your original unique_ptr is likely going to leave scope (and be destroyed) since you are using async asio calls.

Upvotes: 1

Related Questions