Передача владения указателем сокета с помощью tcp::acceptor::async_accept

Недавно я начал использовать Boost.Asio в проекте и хотел бы знать, знает ли кто-нибудь чистое решение для передачи права собственности на вновь созданный сокет на tcp::acceptor::async_accept, что, в свою очередь, передаст это право собственности на accept функция обработчика.

Заметьте, это не бессвязное желание, поскольку обработчик должен вызываться ровно один раз.

Я заметил, что не могу использовать std::bind() и std::unique_ptr‹> в качестве параметра, поскольку std::bind() требует, чтобы его параметры были CopyConstructible, и это правильно. Не только это, но и концепция AcceptHandler Boost также должна быть CopyConstructible.

Итак, мои варианты:

  • Воспользуйтесь устаревшим способом std::auto_ptr‹> для перемещения объектов с помощью конструктора копирования, что может привести к непонятным ошибкам в новых выпусках Boost.Asio.
  • Используйте std::shared_ptr‹> и у вас не будет возможности снять с указателя совместное владение, когда он больше не нужен, т.е. когда он достигает фактической функции обработчика (именно так работа выполняется в примерах в http://www.boost.org/doc/libs/1_43_0/doc/html/boost_asio/examples.html насколько я читал).

or

  • У тебя есть идея получше для меня.

Я в значительной степени в недоумении здесь. Кто-нибудь может просветить меня?


person Gui Prá    schedule 21.06.2010    source источник
comment
Этот вопрос также несколько связан с stackoverflow.com/questions/2835900/   -  person Sam Miller    schedule 26.06.2010
comment
Вы можете найти больше людей, знакомых с boost-asio, в списке рассылки пользователя boost: lists .boost.org/mailman/listinfo.cgi/boost-users   -  person Howard Hinnant    schedule 04.03.2011


Ответы (1)


Я пытался найти способ сделать это с помощью стандартной библиотеки c++0x, но не смог. В конце концов я решил написать собственный удобный класс rvalue_reference_wrapper и rvalue_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();
}

Я не сделал код пуленепробиваемым, но приветствую обсуждение необходимости rvalue_reference_wrapper или того, как смоделировать его с помощью std::reference_wrapper.

Кроме того, для вашего конкретного случая вам, вероятно, потребуется написать другую версию rvalue_reference_wrapper, которая хранит объект по значению, а не по ссылке rvalue, поскольку ваш исходный unique_ptr, вероятно, покинет область (и будет уничтожен), поскольку вы используете асинхронный асио звонит.

person mmocny    schedule 03.03.2011
comment
Ваше решение интересное, но я думаю, что оно небезопасно. Если b никогда не вызывается, указатель никогда не освобождается (поскольку i больше не является владельцем, потому что вы std::move сделали его). Я ошибся? - person Gui Prá; 04.03.2011
comment
сама операция std::move() ничего не делает, она только приводит к ссылке rvalue. - person mmocny; 05.03.2011
comment
Ничего не изменится до тех пор, пока rvalue не будет фактически принят и использован для изменения исходного объекта. В большинстве случаев это означает вызов конструктора перемещения или оператора присваивания перемещения, который безопасно уничтожит исходный объект. Если вы никогда не используете ссылку rvalue, lvalue действует как обычно. Это может привести к висячей ссылке (проблема, которая существует также со ссылками lvalue и std::ref()) - person mmocny; 05.03.2011
comment
Под этим, ведущим к оборванной ссылке, я имел в виду это предлагаемое решение, если b жил дольше, чем i, например (будучи возвращенным из функции или скопированным куда-то). Теперь, когда я думаю об этом, для вашего варианта использования вы будете смотреть на висячую ссылку, поскольку вызов b фактически не выполняется до тех пор, пока не будет оставлена ​​локальная область. Опять же, это не проблема с rvalue_reference_wrapper напрямую, а просто ваш вариант использования, это может произойти с std::ref() в аналогичном сценарии. - person mmocny; 05.03.2011