Boost shared_from_this <>()

может кто-то кратко изложить несколько кратких слов о том, как следует использовать интеллектуальный указатель boost shared_from_this<>(), особенно с точки зрения регистрации обработчиков в io_service с использованием функции bind.

ИЗМЕНИТЬ: В некоторых ответах был задан дополнительный контекст. В принципе, я ищу "gotchas", встречное интуитивное поведение, которое люди наблюдали с использованием этого механизма.

Ответы

Ответ 1

Самый большой "gotcha", с которым я столкнулся, - это незаконность вызова shared_from_this из конструктора. Это следует непосредственно из правила, согласно которому shared_ptr для объекта должен существовать, прежде чем вы сможете вызвать shared_from_this.

Ответ 2

Из моего понимания, иногда в вашем коде вы хотите, чтобы класс предлагал shared_ptr себе, чтобы другие части вашего кода могли получить shared_ptr для объекта вашего класса после его создания.

Проблема в том, что если ваш класс просто имеет shared_ptr<> для себя как переменную-члена, он никогда не будет автоматически разрушен, так как всегда существует "одна последняя ссылка", которая висит вокруг себя. Наследование из enable_shared_from_this дает вашему классу автоматический метод, который возвращает не только shared_ptr, но и содержит только слабый общий указатель в качестве переменной-члена, чтобы не влиять на счетчик ссылок. Таким образом, ваш класс будет освобожден, как обычно, когда последняя ссылка на него исчезнет.

Я никогда не использовал его, но это мое понимание того, как это работает.

Ответ 3

shared_from_this<> используется, если объект хочет получить доступ к shared_ptr<>, указывающему на себя.

Обычно объект знает только о неявном указателе this, но не о каком-либо shared_ptr<> управлении им. Кроме того, this не может быть легко преобразован в shared_ptr<>, который разделяет владение с другими существующими экземплярами shared_ptr<>, поэтому нет простого способа для объекта получить действительный shared_ptr<> для себя.

shared_from_this<> можно использовать для решения этой проблемы. Например:

struct A : boost::enable_shared_from_this<A> {
   server *io;
   // ...

   void register_self() {
      io->add_client(shared_from_this());
   }
};

Ответ 4

Документация boost::asio::io_service destructor объясняет это довольно хорошо

Описанная последовательность разрушения выше позволяет программам упростить их управление ресурсами путем использования shared_ptr < > . Где объект время жизни привязано к времени жизни соединение (или некоторая другая последовательность асинхронные операции), shared_ptr к объекту будут связаны с обработчики для всех асинхронных связанные с ним операции. Эта работает следующим образом:

  • Когда одно соединение заканчивается, все связанные асинхронные операции полный. Соответствующий обработчик объекты уничтожаются, и все Ссылки shared_ptr на объекты уничтожены.
  • Чтобы завершить работу всей программы, вызывается функция stop() io_service прекратить любые вызовы run() насколько это возможно. Деструктор io_service определенный выше, уничтожает все обработчики, вызывая все ссылки shared_ptr все объекты подключения уничтожены.

Обычно ваши объекты связывают асинхронные операции, когда обработчики привязаны к функциям-членам с помощью boost::bind и boost::shared_from_this(). Есть несколько примеров, которые используют эту концепцию.

Ответ 5

Материал отсутствует в некоторых комментариях выше. Вот пример, который мне помог:

Увеличить enable_shared_from_ в этом примере

Для меня я боролся с ошибками о плохих слабых указателях. Вы ДОЛЖНЫ разместить свой объект в виде shared_ptr:

class SyncSocket: public boost::enable_shared_from_this<SyncSocket>

И выделите один из них следующим образом:

boost::shared_ptr<SyncSocket> socket(new SyncSocket);

Тогда вы можете сделать что-то вроде:

socket->connect(...);

Множество примеров показывают, как использовать shared_from_this() примерно так:

boost::asio::async_read_until(socket, receiveBuffer, haveData,
        boost::bind(&SyncSocket::dataReceived, shared_from_this(), boost::asio::placeholders::error));

Но мне не хватало использовать shared_ptr для выделения объекта для начала.