【问题标题】:Accessing data from buffer created from boost从 boost 创建的缓冲区访问数据
【发布时间】:2019-08-14 13:03:19
【问题描述】:

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

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 个值是垃圾。从错误的起始地址读取向量。代码有什么问题?

【问题讨论】:

  • 我把它改成了“NumOfChannels”避免混淆..!
  • 我不太熟悉指针算术魔术,但我对reinterpret_cast&lt;const float*&gt;(_begin )) + (sizeof(uint32_t) * (GetChannelCount() + Index::SIZE)) 感到困惑。您首先将指向 uint32_t 的指针转换为指向浮点数的指针,然后尝试推进整数字节。它在这一点上运作良好吗?据我记得,指针添加需要相同的类型,所以在这里你应该先将地址提前到 int 数组的末尾,然后将指针转换为 float。
  • uint32_t OFFSET = sizeof(uint32_t) * (GetChannelCount() + LidarMeasurement::Index::SIZE); begin_azi = const_cast&lt;float*&gt;(reinterpret_cast&lt;const float*&gt;(_begin + OFFSET)); 即使这样也行不通
  • GetTotalPointCount() 是什么?当您尝试调用 GetAzimuth 时,它的返回值是否大于或等于 104?
  • 回到指针算术魔术。您不应该真正向编译器显示一个元素占用了多少字节,因此 sizeof(uint32_t) 处的元素数量相乘是不必要的。编译器应该只通过元素的类型和元素的数量来扣除它。 begin_azi = const_cast&lt;float*&gt;(reinterpret_cast&lt;const float*&gt;(_begin + GetChannelCount() + LidarMeasurement::Index::SIZE)); 请让我知道这条评论是否更有用。

标签: c++ vector boost buffer


【解决方案1】:

问题是bt错误的开始地址计算造成的。

begin_azi = const_cast&lt;float*&gt;(reinterpret_cast&lt;const float*&gt;(_begin )) + (sizeof(uint32_t) * (GetChannelCount() + Index::SIZE));

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

2) pointer to uint32_t 类型应该计算地址偏移量,然后才转换为 pointer to float 类型。

begin_azi 的正确方式应该是这样的:

begin_azi = const_cast&lt;float*&gt;(reinterpret_cast&lt;const float*&gt;(_begin + GetChannelCount() + Index::SIZE));

为什么它早些时候部分工作?来自cppreference

指针算法

如果指针P指向索引为I的数组元素,那么

  • P+N 和 N+P 是指向同一数组中索引为 I+N 的元素的指针
  • P-N 是一个指针,指向同一个数组的元素,索引为 {tt|I-N}}

只有当原始指针和结果指针都指向同一个数组的元素或该数组的末尾一个时,才定义行为。

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

【讨论】:

  • P.S.正如我在对该问题的评论中所说,我对这种操作并不十分熟悉,但我希望它们应该以这种方式工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-14
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
  • 1970-01-01
相关资源
最近更新 更多