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

标签 c++ vector boost buffer

我正在尝试访问使用 boost 缓冲区函数序列化的数据,并希望将其填充到两个 vector 中。我在填充第二个 vector 的地址时遇到问题。下面的类(class)展示了这两个 vector 以及它们是如何填充的。

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);
  }

收到序列化数据后,我需要将方位角放回 vector 。 我正在使用以下函数来获取 vector 。 _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 个值是垃圾值。从错误的起始地址读取 vector 。代码有什么问题?

enter image description here

最佳答案

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

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计算错误后指出。所以没有人保证程序会以正确或错误的方式执行。

关于c++ - 从 boost 创建的缓冲区访问数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57495300/

相关文章:

java - 使用 vector jswing 获取正确的表格标题

xml - 删除 boost xml 序列化的版本控制

c++ - 类名后的模板参数是什么意思?

c++ - 编译器无法识别 std::vector 的成员初始值设定项

c++ - 何时通过指针或shared_ptr传递

vector - 如何从 Racket 中的向量中获取最小整数

c++ - 从结构类型的 vector 中删除一个元素

c++ - 如果存在则返回一个成员变量

c++ - 将 char* 输出到 std::string C++

c++ - 将结构从 C 转换为 C++ (POD)