提问者:小点点

使用std::vector时,简单增强UDP接收器gest堆释放后使用


我很难理解为什么我非常简单的UDP接收器会出现使用后无堆错误(由ASAN诊断)。其思想是侦听传入数据包的可配置数量的本地端口。

我在这里发布了一个简化版的课程

UdPreceVer.hpp

class UdpReceiver
{
  public:
    UdpReceiver(std::vector<int> listen_ports);
    void run();
  protected:
    boost::asio::io_service m_io;
    char m_receive_buffer[MAX_RECEIVE_LENGTH];
    std::vector<udp::endpoint> m_endpoints;
    std::vector<udp::socket> m_sockets;
    void handleUdpData(const boost::system::error_code& error, size_t bytes_recvd, int idx);

}; 

UdPreceVer.cpp

UdpReceiver::UdpReceiver(std::vector<int> listen_ports) : 
  m_io()
{ 
  
  int idx = 0;
  try {
  for (auto port: listen_ports) {
    m_endpoints.push_back(udp::endpoint(udp::v4(), port));
    m_sockets.push_back(udp::socket(m_io, m_endpoints[idx]));
    m_sockets[idx].async_receive_from(
      boost::asio::buffer(m_receive_buffer, MAX_RECEIVE_LENGTH), m_endpoints[idx],
      boost::bind(&MessageParser::handleUdpData, this,
      boost::asio::placeholders::error,
      boost::asio::placeholders::bytes_transferred,
      idx)
    );
    idx++;
  }
  } catch(const std::exception &exc) 
  {
    std::cerr <<exc.what();
    exit(-1);
  }
}

根据ASAN,m_endpoints.push_back(udp::endpoint(udp::v4(),port))分配了一些动态内存,稍后的迭代会再次释放这些内存。这最终给了我免费后的使用,这会以一种不可预测的方式把我的应用程序搞乱。

我真的不明白在这种情况下使用std::vector怎么会不起作用。有什么想法吗?


共1个答案

匿名用户

async_receive_from的文档说明:“sender_endpoint对象的所有权由调用方保留,调用方必须保证在调用处理程序之前该对象是有效的。”

您的push_back可能会重新分配基础存储,从而使async_receive_from保留一个悬空引用。

要避免重新分配,请在进入循环之前为必要数量的元素保留空间:

m_endpoints.reserve(listen_ports.size());
m_sockets.reserve(listen_ports.size());