从 boost 创建的缓冲区访问数据

Accessing data from buffer created from boost

我正在尝试访问使用 boost 缓冲区函数序列化的数据,并希望将其填充到两个向量中。我在填充第二个向量的地址时遇到问题。以下 class 显示了两个向量及其填充方式。

class LidarMeasurement {
  private:
    std::vector<uint32_t> _header;
    std::vector<float> _azimuth;

  public:

    //The header consists of an array of uint32_t's in the following layout
    enum Index : size_t {
         HorizontalAngle,
         ChannelCount,
         SIZE
         };

    explicit LidarMeasurement(uint32_t NumOfChannels = 0u): _header(Index::SIZE + NumOfChannels, 0u) {
        _header[Index::ChannelCount] = NumOfChannels;
    }

    // called before filling vectors
    void Reset(uint32_t total_point_count) {
        std::memset(_header.data() + Index::SIZE, 0, sizeof(uint32_t) * GetChannelCount());
        _azimuth.clear();
        _azimuth.reserve(total_point_count);
    }

    // after reset,Write point function starts filling vectors.. following function is called 104 times (not constant) before next reset
    void WritePoint(uint32_t channel, float angle_hor) {
        _header[Index::SIZE + channel] += 1u;
        _azimuth.emplace_back(angle_hor);
    }

    uint32_t GetChannelCount() const {
       return _header[Index::ChannelCount];
    }
}

一旦它们被填满,它就会被序列化并发送给客户端。它使用以下函数序列化:

template <typename Sensor>
  inline Buffer LidarSerializer::Serialize(
      const Sensor &,
      const LidarMeasurement &measurement,
      Buffer &&output) {
    std::array<boost::asio::const_buffer, 2u> seq = {
        boost::asio::buffer(measurement._header),
        boost::asio::buffer(measurement._azimuth)};
    output.copy_from(seq);
    return std::move(output);
  }

收到序列化数据后,我需要将方位角放回矢量。 我正在使用以下函数来获取向量。 _begin 是缓冲区的地址。

std::vector<float> GetAzimuth(const uint32_t* _begin) const{
      std::vector<float> localAzimuthMemCopy;
      begin_azi = const_cast<float*>(reinterpret_cast<const float*>(_begin )) + (sizeof(uint32_t) * (GetChannelCount() + Index::SIZE));
      end_azi = begin_azi + GetTotalPointCount();//Total point count is the addition of individual channel point counts (not shown here)
      for(float* i = begin_azi; i < end_azi; i++){
        localAzimuthMemCopy.emplace_back(*i);
      }
      return localAzimuthMemCopy;
    }

但是,我得到的结果有一个内存偏移量。我得到 104 个值,但最后 18 个值是垃圾值。从错误的起始地址读取向量。代码有什么问题?

问题是开始地址计算错误导致的。

begin_azi = const_cast<float*>(reinterpret_cast<const float*>(_begin )) + (sizeof(uint32_t) * (GetChannelCount() + Index::SIZE));

1)指针运算只需要指针和元素个数就可以前进。编译器应根据指针类型自行扣除的字节数。所以 sizeof(uint32_t) 处的乘法是多余的。正确的指针前进方式见float* end_azi = begin_azi + GetTotalPointCount();

2) 指向uint32_t类型的指针需要计算地址偏移量,然后才转换为指向float的指针类型。

所以 begin_azi 的正确方法应该是这样的:

begin_azi = const_cast<float*>(reinterpret_cast<const float*>(_begin + GetChannelCount() + Index::SIZE));

为什么它之前部分起作用了?来自 cppreference

Pointer arithmetic

If the pointer P points at an element of an array with index I, then

  • P+N and N+P are pointers that point at an element of the same array with index I+N
  • P-N is a pointer that points at an element of the same array with index {tt|I-N}}

The behavior is defined only if both the original pointer and the result pointer are pointing at elements of the same array or one past the end of that array.

谁也不知道begin_azi计算错了指向哪里了。所以没有人保证程序会以正确或错误的方式执行。