了解共享指针的问题(生命周期,作为参数传递)

时间:2018-01-05 08:50:52

标签: c++11 boost-asio shared-ptr coredump

我尝试从boost asio chat示例开始,并派生出一个自己的网络程序。不幸的是,我有一些问题,了解真正发生的事我试图将我的程序减少到最低限度。服务器类等待传入连接并创建会话对象以处理连接。这是服务器的代码:

#include <cstdint>
#include <iostream>
#include <sstream>
#include <memory>
#include <vector>

#include <boost/asio.hpp>
#include <boost/bind.hpp>

class Session : public std::enable_shared_from_this<Session>
{
public:
    Session(boost::asio::ip::tcp::socket __oSocket);
    virtual ~Session();
    void StartSession();
private:
    void StartRecv();
    std::vector<int32_t> m_vecSetupReceiveBuffer;
    boost::asio::ip::tcp::socket m_oSocket;
};

Session::Session(boost::asio::ip::tcp::socket __oSocket) :
    m_vecSetupReceiveBuffer({2}),
    m_oSocket(std::move(__oSocket))
{    }

Session::~Session()
{
    std::cout << "Deleted session" << std::endl;
}

void Session::StartSession()
{
    auto self(shared_from_this());
    std::cout << "StartSession()" << std::endl;
    boost::asio::async_write(m_oSocket, boost::asio::buffer(m_vecSetupReceiveBuffer),
    [this, self](boost::system::error_code _oError, std::size_t)
    {
        std::cout << m_vecSetupReceiveBuffer.size() << std::endl;
        StartRecv();
    });
}

void Session::StartRecv()
{
    auto self(shared_from_this());
    std::cout << "StartRecv()" << std::endl;
    boost::asio::async_read(m_oSocket, boost::asio::buffer(m_vecSetupReceiveBuffer),
    [this, self](boost::system::error_code _oError, std::size_t)
    {});
}

class Server
{
public:
    Server(boost::asio::io_service& _rIOService, uint32_t _nPort);
    virtual ~Server();
private:
    void StartAccept();
    boost::asio::ip::tcp::acceptor m_oAcceptor;
    boost::asio::ip::tcp::socket m_oSocket;
};

Server::Server(boost::asio::io_service& _rIOService, uint32_t _nPort) :
    m_oAcceptor(_rIOService, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), _nPort)),
    m_oSocket(_rIOService)
{
    StartAccept();
}

Server::~Server()
{}

void Server::StartAccept()
{
    m_oAcceptor.async_accept(m_oSocket,
    [this](boost::system::error_code _oError)
    {
        std::make_shared<Session>(std::move(m_oSocket))->StartSession();
        StartAccept();
    });
}


int main(int argc, char* argv[])
{
    boost::asio::io_service _oIOServerService;
    std::shared_ptr<Server> _pServer(std::make_shared<Server>(_oIOServerService, 2000));
    _oIOServerService.run();
    return 0;
}

这段代码按预期运行,但是当我尝试调整一些东西并稍微玩一下时,我发现我不明白何时真正创建和删除共享指针以及存储它们的位置。例如,我尝试将std::make_shared<Session>(std::move(m_oSocket))->StartSession();更改为std::make_shared<Session>(std::move(m_oSocket));,并在Session类的构造函数中添加了StartSession();。如果我运行代码然后抛出

terminate called after throwing an instance of 'std::bad_weak_ptr'
what():  bad_weak_ptr
Aborted (core dumped)

这可能发生在auto self(shared_from_this());。但我不明白为什么?我应该在代码中更改什么?所以我认为我的问题是我不明白如何正确使用shared_ptr,如何在这些结构中使用它,我可以访问它以及如何使它可访问。此外,我不清楚为什么有时必须使用this以及何时使用shared_from_this()。是否有一个很好的教程,或简单的经验法则?

我也不清楚,为什么有些用户使用lambda函数表示法,有些用boost::bind表示法有什么区别?

请原谅我的新手问题,我试图在教程中找到一些信息,但我只是混淆了这些共享指针和boost :: asio。似乎总是做一些奇怪的事情。

1 个答案:

答案 0 :(得分:0)

您获得std::bad_weak_ptr,因为在构建shared_ptr期间没有this拥有Session。您仍然在make_shared的正文中,并且尚未创建shared_ptr

shared_from_this()仅在Session的实例中可用,它是一个成员函数。您通过派生std::enable_shared_from_this继承了它。

lambda由self的副本构成,Session的成员可用 - 如果this也指向Session对象,而不是lambda对象,因为this捕获