【问题标题】:Segmentation fault in handlers with shared_ptr's带有 shared_ptr 的处理程序中的分段错误
【发布时间】:2020-05-03 23:55:04
【问题描述】:

我正在尝试创建一个代理,该代理仅适用于应用程序执行中的第一个会话。它捕获 SIGSEGV 试图处理第二个。

下一个方法:

  • 客户端连接
  • 代理连接到终端服务器(每个会话的唯一连接)
  • 代理向服务器发送数据,从服务器获取处理过的数据,并将处理过的数据发送给客户端
  • 代理断开与服务器和客户端的连接

问题是当我们启动应用程序并且第一个客户端尝试使用代理时,它工作正常(假设客户端始终连接到代理,例如第一个获取其数据,断开连接,然后第二个连接)。但是当第二个尝试在此之后连接时,执行甚至无法到达handleAccept 并在__atomic_add 函数中捕获SIGSEGV atomicity.h(我在Linux 中工作)。

我无法理解我错误地制作了处理程序,错误地使用了shared_ptr,或两者兼而有之。

run 在创建Proxy 对象后调用一次,以使其接受并处理客户端连接:

void Proxy::run() // create the very first session and keep waiting for other connections
{
    auto newSession = std::make_shared<Session>(ioService_);

    acceptor_.async_accept(
        newSession->getClientSocket(),
        [&](const boost::system::error_code &error) // handler is made according to boost documentation
        {
            handleAccept(newSession, error);
        }
    );

    ioService_.run();
}

handleAccept 做了几乎相同的事情,但也使会话开始在客户端和端服务器之间传输数据:

void Proxy::handleAccept(std::shared_ptr<Session> session, const boost::system::error_code &error) // handle the new connection and keep waiting other ones
{
    if (!error)
    {
        session->connectToServer(serverEndpoint_);
        session->run(); // two more shared_ptr's to session are appeared here and we just let it go (details are further)
    }

    auto newSession = std::make_shared<Session>(ioService_);

    acceptor_.async_accept(
        newSession->getClientSocket(),
        [&](const boost::system::error_code &error)
        {
            handleAccept(newSession, error);
        }
    );
}

Session 包含两个Socket 对象(服务器和客户端),每个对象都有shared_ptr。当他们每个人都完成所有操作或发生一些错误时,他们reset 他们的shared_ptr 进入会话,因此它被解除分配。

【问题讨论】:

  • 通过引用捕获的 lambda 是可疑的——您将捕获对本地 newSession 变量的引用,该变量将在包含函数返回后悬空。您不需要 lambda 来修改本地,那么为什么要通过引用捕获?尝试按值捕获(在两个 lambda 中将 [&amp;] 更改为 [=]

标签: c++ boost shared-ptr gnu


【解决方案1】:

为什么你在 handleAccept(...) 中通过引用来使用/捕获局部变量?:

 acceptor_.async_accept(
        newSession->getClientSocket(),
        [&](const boost::system::error_code &error)
        {
            handleAccept(newSession, error);
        }
    );

您想使用:

 acceptor_.async_accept(
        newSession->getClientSocket(),
        [this, newSession](const boost::system::error_code &error)
        {
            handleAccept(newSession, error);
        }
    );

函数完成后会运行lambda,在此之前会销毁局部变量newSession。

【讨论】:

  • 我正要说同样的话! newSession 超出范围,所以你留下了悬空的参考
猜你喜欢
  • 2018-11-18
  • 2020-06-15
  • 2019-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-13
相关资源
最近更新 更多