shared_from_this使用boost :: asio抛出bad_weak_ptr

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了shared_from_this使用boost :: asio抛出bad_weak_ptr相关的知识,希望对你有一定的参考价值。

首先,我已阅读列出的所有相关问题。

他们说,“在使用shared_from_this之前,你必须拥有一个现有的shared_ptr。”据我所见,我无法违反这一条件。我将Foo的实例创建为shared_ptr,并强制它始终创建为shared_ptr。然后,我将shared_ptr存储在一个集合中。然而,当调用shared_from_this时,我仍然得到bad_weak_ptr异常。

#pragma once

#include <memory>
#include <vector>

//--------------------------------------------------------------------
class Foo : std::enable_shared_from_this<Foo>
{
public:

    typedef std::shared_ptr<Foo> SharedPtr;

    // Ensure all instances are created as shared_ptr in order to fulfill requirements for shared_from_this
    static Foo::SharedPtr Create()
    {
        return Foo::SharedPtr(new Foo());
    };

    Foo(const Foo &) = delete;
    Foo(Foo &&) = delete;
    Foo & operator = (const Foo &) = delete;
    Foo & operator = (Foo &&) = delete;
    ~Foo() {};

    // We have to defer the start until we are fully constructed because we share_from_this()
    void Start()
    {
        DoStuff();
    }

private:

    Foo() {}

    void DoStuff()
    {
        auto self(shared_from_this());
    }
};

//--------------------------------------------------------------------
int main()
{
    std::vector<Foo::SharedPtr> foos;
    Foo::SharedPtr foo = Foo::Create();
    foos.emplace_back(foo);
    foo->Start();

    return 0;
}
答案

您必须根据enable_shared_from_this说明符继承public

公开继承自std :: enable_shared_from_this为类型T提供了成员函数shared_from_this。

来自http://en.cppreference.com/w/cpp/memory/enable_shared_from_this

所以写

class Foo : public std::enable_shared_from_this<Foo>
另一答案

首先,你在发布工作之前启动线程,所以io_service::run()DoAccept实际完成之前很容易完成。

接下来,基类必须是PUBLIC才能使enable_shared_from_this工作:

class Connection : public std::enable_shared_from_this<Connection> {

工作自包含代码:

#include <iostream>
#include <mutex>
namespace SomeNamespace{
struct Logger {
    enum { LOGGER_SEVERITY_INFO };
    void Log(std::string const& msg, std::string const& file, unsigned line, int level) const {
        static std::mutex mx;
        std::lock_guard<std::mutex> lk(mx);
        std::cout << file << ":" << line << " level:" << level << " " << msg << "
";
    }
    template <typename... Args>
    void LogF(std::string const& msg, Args const&... args) const {
        static std::mutex mx;
        std::lock_guard<std::mutex> lk(mx);
        static char buf[2048];
        snprintf(buf, sizeof(buf)-1, msg.c_str(), args...);
        std::cout << buf << "
";
    }
    static Logger &GetInstance() {
        static Logger This;
        return This;
    }
};
} // namespace Somenamespace

#include <boost/asio.hpp>

#include <atomic>
#include <condition_variable>
#include <memory>

//--------------------------------------------------------------------
class ConnectionManager;

//--------------------------------------------------------------------
class Connection : public std::enable_shared_from_this<Connection> {
  public:
    typedef std::shared_ptr<Connection> SharedPtr;

    // Ensure all instances are created as shared_ptr in order to fulfill requirements for shared_from_this
    static Connection::SharedPtr Create(ConnectionManager *connectionManager, boost::asio::ip::tcp::socket &socket);

    Connection(const Connection &) = delete;
    Connection(Connection &&) = delete;
    Connection &operator=(const Connection &) = delete;
    Connection &operator=(Connection &&) = delete;
    ~Connection();

    // We have to defer the start until we are fully constructed because we share_from_this()
    void Start();
    void Stop();

    void Send(const std::vector<char> &data);

  private:
    ConnectionManager *m_owner;
    boost::asio::ip::tcp::socket m_socket;
    std::atomic<bool> m_stopped;
    boost::asio::streambuf m_receiveBuffer;
    mutable std::mutex m_sendMutex;
    std::shared_ptr<std::vector<boost::asio::const_buffer> > m_sendBuffers;
    bool m_sending;

    std::vector<char> m_allReadData; // for testing

    Connection(ConnectionManager *connectionManager, boost::asio::ip::tcp::socket socket);

    void DoReceive();
    void DoSend();
};

//--------------------------------------------------------------------

//#include "Connection.h"
//#include "ConnectionManager.h"
//**ConnectionManager.h **

//#pragma once

//#include "Connection.h"

// Boost Includes
#include <boost/asio.hpp>

// Standard Includes
#include <thread>
#include <vector>

//--------------------------------------------------------------------
class ConnectionManager {
  public:
    ConnectionManager(unsigned port, size_t numThreads);
    ConnectionManager(const ConnectionManager &) = delete;
    ConnectionManager(ConnectionManager &&) = delete;
    ConnectionManager &operator=(const ConnectionManager &) = delete;
    ConnectionManager &operator=(ConnectionManager &&) = delete;
    ~ConnectionManager();

    void Start();
    void Stop();

    void OnConnectionClosed(Connection::SharedPtr connection);

  protected:
    boost::asio::io_service m_io_service;
    boost::asio::ip::tcp::acceptor m_acceptor;
    boost::asio::ip::tcp::socket m_listenSocket;
    std::vector<std::thread> m_threads;

    mutable std::mutex m_connectionsMutex;
    std::vector<Connection::SharedPtr> m_connections;

    void IoServiceThreadProc();

    void DoAccept();
};

//--------------------------------------------------------------------

#include <boost/bind.hpp>

#include <algorithm>

//--------------------------------------------------------------------
Connection::SharedPtr Connection::Create(ConnectionManager *connectionManager, boost::asio::ip::tcp::socket &socket) {
    return Connection::SharedPtr(new Connection(connectionManager, std::move(socket)));
}

//--------------------------------------------------------------------
Connection::Connection(ConnectionManager *connectionManager, boost::asio::ip::tcp::socket socket)
        : m_owner(connectionManager), m_socket(std::move(socket)), m_stopped(false), m_receiveBuffer(), m_sendMutex(),
          m_sendBuffers(), m_sending(false), m_allReadData() {}

//--------------------------------------------------------------------
Connection::~Connection() {
    // Boost uses RAII, so we don't have anything to do. Let thier destructors take care of business
}

//--------------------------------------------------------------------
void Connection::Start() { DoReceive(); }

//--------------------------------------------------------------------
void Connection::Stop() {
    // The entire connection class is only kept alive, because it is a shared pointer and always has a ref count
    // as a consequence of the outstanding async receive call that gets posted every time we receive.
    // Once we stop posting another receive in the receive handler and once our owner release any references to
    // us, we will get destroyed.
    m_stopped = true;
    m_owner->OnConnectionClosed(shared_from_this());
}

//--------------------------------------------------------------------
void Connection::Send(const std::vector<char> &data) {
    std::lock_guard<std::mutex> lock(m_sendMutex);

    // If the send buffers do not exist, then create them
    if (!m_sendBuffers) {
        m_sendBuffers = std::make_shared<std::vector<boost::asio::const_buffer> >();
    }

    // Copy the data to be sent to the send buffers
    m_sendBuffers->emplace_back(boost::asio::buffer(data));

    DoSend();
}

//--------------------------------------------------------------------
void Connection::DoSend() {
    // According to the boost documentation, we cannot issue an async_write while one is already outstanding
    //
    // If that is the case, it is OK, because we've added the data to be sent to a new set of buffers back in
    // the Send method. Notice how the original buffer is moved, so therefore will be null below and how Send
    // will create new buffers and accumulate data to be sent until we complete in the lamda
    //
    // When we complete in the lamda, if we have any new data to be sent, we call DoSend once again.
    //
    // It is important though, that DoSend is only called from the lambda below and the Send method.

    if (!m_sending && m_sendBuffers) {
        m_sending = true;
        auto copy = std::move(m_sendBuffers);
        auto self(shared_from_this());

        boost::asio::async_write(m_socket, *copy,
             [self, copy](const boost::system::error_code &errorCode, size_t bytes_transferred) {
                 std::lock_guard<std::mutex> lock(self->m_sendMutex);
                 self->m_sending = false;

                 if (errorCode) {
                     // An error occurred
                     return;
                 }

       

以上是关于shared_from_this使用boost :: asio抛出bad_weak_ptr的主要内容,如果未能解决你的问题,请参考以下文章

C++ shared_from_this() 不会让 obj 被破坏

使用 shared_from_this 参数等待 std::future 获取 std::async 会阻止对 this 的破坏

shared_from_this

为什么调用shared_from_this调用std :: terminate

shared_from_this()如何在派生类中工作,该派生类继承自从enabled_shared_from_this继承的基类

智能指针shared_ptr新特性shared_from_this及weak_ptr