我正在尝试访问使用 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 。代码有什么问题?
最佳答案
问题是开始地址计算错误导致的
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/