конструктор перемещения делает недействительным shared_from_this - PullRequest
1 голос
/ 07 июня 2019

Я хотел бы начать поток с классом, который содержит не подлежащие копированию члены.Для связи с потоком я хотел бы создать общий указатель из объекта, прежде чем переместить его в поток.

Делает ли конструктор перемещения недействительным общий указатель?Если так, то каков элегантный способ сделать это на c ++?Одним из решений было бы обернуть MessageClient в общий указатель, но это взломало конструктор перемещения.

class MessageClient : public std::enable_shared_from_this<MessageClient> {
private:
    boost::asio::io_context io_context;

    void send() {
      // code
    }

    void operator() () {
      // code
    }
};

int main () {
   MessageClient client;
   auto pclient = client.shared_from_this();
   std::thread thread(std::move(client));

   pclient->send(); // terminate called after throwing an instance of  'std::bad_weak_ptr'
                    // what():  bad_weak_ptr
                    // Aborted (core dumped)
   thread.join();
}

EDIT

Я получил свой ответ.Теперь я понимаю, что неправильно использовал enable_shared_from_this, но реальный ответ заключается в том, что нет способа решить проблему, которая не включает в себя перенос объекта в другой объект, такой как умный указатель или лямбда-функция (которая заключает в себеобъект в функтор).Лично я нашел второе решение проще, поэтому я выбрал его.

MessageClient client;
std::thread thread([&client](){client.run();});

client.send();

EDIT2

Я нашел более очевидное решение.Если я создаю ссылку на объект, мне не нужно ее переносить:

MessageClient client;
std::thread thread(std::ref(client));

client.send();

Ответы [ 2 ]

1 голос
/ 07 июня 2019

Вывод из enable_shared_from_this намекает на то, что каждый экземпляр принадлежит некоторым shared_ptr s. Ваша проблема в том, что client нет, и не связано с перемещением его в поток.

У вас есть неопределенное поведение в этой строке:

auto pclient = client.shared_from_this();

Просто используйте std::shared_ptr<MessageClient> с самого начала.

class MessageClient {
private:
    boost::asio::io_context io_context;

    void send() {
      // code
    }

    void operator() () {
      // code
    }
};

int main () {
   auto pclient = std::make_shared<MessageClient>();
   std::thread thread([pclient]() { (*pclient)(); });

   pclient->send(); 

   thread.join();
}
1 голос
/ 07 июня 2019

В main вы можете создать два экземпляра shared_ptr, которые совместно используют один и тот же MessageClient объект. Один общий ptr может быть перемещен в тело потока, другой остается в main, и вы можете использовать его для связи с потоком:

int main () 
{
   std::shared_ptr<MessageClient> client = std::make_shared<MessageClient>();
   std::shared_ptr<MessageClient> pclient = client;

   std::thread thread(
        [client = std::move(client)]()
        {
           (*client)(); // invoke body of thread
        });

   pclient->send(); // works fine
   thread.join();
}

демо


Ваш код с shared_from_this не работает, потому что shared_from_this можно вызывать только внутри функции-члена MessageClient, когда вы уверены, что есть хотя бы один экземпляр shared_ptr, который управляет this.

...