【问题标题】:"String iterator not dereferncable" with boost async_read_some带有 boost async_read_some 的“字符串迭代器不可取消引用”
【发布时间】:2017-11-26 18:58:14
【问题描述】:

我有一个服务器,它使用来自 boost 的异步套接字和一个“接受”函数,如下所示(“用户”几乎等同于 this 示例中的“会话”):

    accept()
{
    this->_acceptor.async_accept(this->_socket, [this](boost::system::error_code error)
    {
        if (!error)
        {
            make_shared<User>(move(_socket), *this)->read();
        }
        accept();
    });
}

一个“读取”函数如下(_readData是一个1024的char数组):

    void User::read()
{
    auto self(shared_from_this());
    this->_socket.async_read_some(boost::asio::buffer(this->_readData, 1024),
        [this, self](boost::system::error_code error, size_t length)
    {
        if (!error)
        {
            this->buildReceivedMessage(string(this->_readData, length));
            this->read();
        }
    });
}

还有一个“写”功能。

当我用客户端连接到服务器时,从客户端到服务器的第一次传输顺利进行,服务器按预期发回响应。然后,我一步步往代码里走,read函数完成后,代码进入了几个我不认识的头文件,最终抛出“表达式:无法取消引用字符串迭代器,因为迭代器失效(例如发生了重新分配) , 或字符串被破坏)”来自xstring 文件的断言问题。对于我的一生,我不知道为什么。

编辑 1: buildReceivedMessage 创建一个ReceivedMessage,它以易于访问的格式包含请求的值,然后将其转发给messageHandler,后者根据其类型转发请求。 例如,第一个请求是登录请求,所以 ReceivedMessage 最终会出现在这个函数中:

void User::handleSignin(shared_ptr<ReceivedMessage> msg)
{
    vector<string> values = msg->getValues();
    if (this->_server.getDB().isUserAndPassMatch(values[0], values[1]))
    {
        if (this->getUserByName(values[0]))
        {
            this->write("1022");
        }
        else
        {
            this->_server.addUser(shared_ptr<User>(this));
            this->write("1020");
            this->_username = values[0];
        }
    }
    else
    {
        this->write("1021");
    }
}

【问题讨论】:

  • 可能是在读取功能中 - 在接收时打印出长度和错误代码?也许这会给你一些线索?
  • @Nim 尝试这样做,输出为:“system:0 (error) 16 (length of the data, which is correct)”。
  • 哪个编译器/增强版本?
  • @Nim boost 1.64.0, msvc 编译器
  • 问题不在于您发布的代码,很可能在于您未发布的代码 - build... 方法中会发生什么?

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


【解决方案1】:

在:

void User::read()
{
    auto self(shared_from_this());
    this->_socket.async_read_some(boost::asio::buffer(this->_readData, 1024),
        [this, self](boost::system::error_code error, size_t length)
    {
        if (!error)
        {
            this->buildReceivedMessage(string(this->_readData, length));
            this->read();
        }
    });
}

您依靠 shared_ptr self 来保持连接。这很好,但buildReceivedMessage() 是否也为self 创建了一个shared_ptr?

handleSignin() 没有收到 shared_ptr,这让我怀疑你的对象 self,即this,真的被过早地销毁了。

我会首先尝试在User::read() 中使用self 而不是this,以确保self 的捕获不会被优化掉(是的,这是可能的)。我还要确保不要仅仅依靠读取循环来保持连接处于活动状态。

【讨论】:

    【解决方案2】:

    我遇到了类似的问题,ASIO 的一些读/写函数引用了您提供的可变缓冲区,并要求缓冲区在async 函数完成之前是持久的。使用字符串作为字符缓冲区,例如传递asio::buffer(std::string("data")) 将导致此断言,因为在asio 处理async 函数时字符串已超出范围。也就是说,查看所有读/写函数并确保将字符串作为可变缓冲区传递到何处,该字符串是持久的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-30
      • 1970-01-01
      • 2012-07-25
      • 2015-12-11
      • 2015-01-13
      • 1970-01-01
      • 2016-01-25
      相关资源
      最近更新 更多