在缓冲区之间移动字节时出现意外结果

Posted

技术标签:

【中文标题】在缓冲区之间移动字节时出现意外结果【英文标题】:Unexpected result when moving bytes between buffers 【发布时间】:2016-07-26 15:59:16 【问题描述】:

我正在使用 c++ 编写一个函数,其目的是将num_bytes 从一个向量移动到另一个向量。

这是我函数的相关部分

// Grab a pointer to the vector currently in use
std::vector<unsigned char> *bytes = &currentBuffer();

// Calculate un-parsed data in current vector                             
size_t num_bytes = static_cast<size_t>(currentBuffer().size() - pos_);

// Added in to test that it is working
std::cout << "Byte before: " << (*bytes)[pos_] << std::endl;

// Move num_bytes from pos_ in currentVector to [0] in otherBuffer
if (num_bytes)                                               
   memmove(&(otherBuffer()[0]), &((*bytes)[pos_]), num_bytes);
                                                             

// I now want to use otherBuffer as currentBuffer
bytes = &otherBuffer();                                            

// Reset size of new buffer
bytes->resize(num_bytes);                                     

// Reset position of new buffer
pos_ = 0;

// Added in to test that it is working                                   
std::cout << "Byte after: " << (*bytes)[pos_] << std::endl;

当我使用真实数据运行它时,我从两个 cout 语句中得到两个不同的结果,理想情况下,currentVector[pos_]otherVector[0] 的字节值在 memmove 之后应该是相同的。

任何线索可能会出错吗?我认为错误在memmove 之内,但我无法弄清楚它可能是什么。

谢谢!

【问题讨论】:

您的代码可以大大简化。例如,尝试使用 C++ 提供的工具复制一个范围:vector&lt;unsigned char&gt; result(source.begin() + start_index, source.begin() + start_index + count); @JimV - 这似乎有效:otherBuffer() = std::vector&lt;unsigned char&gt;(bytes-&gt;begin() + pos_, bytes-&gt;begin() + pos_ + num_bytes); 不过我有一个问题:这个新向量是否与 otherBuffer() 占用相同的内存位置(返回对向量的引用)。如果没有,有什么办法可以做到吗? 你到底为什么想要那个?目前尚不清楚您要做什么,或者为什么要以如此复杂的方式进行。 我正在尽量减少我必须做的内存分配量。这些向量实际上会很大,理想情况下,我应该能够在创建包含向量的对象时执行vector.reserve() 之类的操作,以一次获取大量空间,然后重新使用内存 【参考方案1】:

您需要在将数据复制到之前调整缓冲区的大小,否则可能会超出其他向量的内部分配缓冲区。

不过,最好使用经典的 C++ 方法:

otherBuffer().assign(currentBuffer().begin() + pos, currentBuffer().end());

您所需要的一切 - 无需调整大小,无需 memmove(无论如何,在这种情况下,memcpy 可能会更有效......)。

【讨论】:

矢量已调整大小 - 我在程序开始时执行 vector.reserve(large_size_here) 以分配大量空间一次。理想情况下,我不应该进行另一次分配,只需重用最初保留的内存。 @wKavey reserve resize 相同。您已分配内存,但 vector 尚未初始化这些位置。当它发生时,你可能放在那里的任何东西都会被清除。 我不关心被擦除的数据 - 这样做的想法是内存是可重复使用的,我不关心可能存在的“旧”数据。如果我没有多大意义,请原谅我,我可能只是在这里没有掌握一些基本概念 看看resize() - 还有一个额外的默认参数!这将用于填写数据,如果大小增加,在这种情况下会覆盖您已经填写的数据。另一方面,如果内部缓冲区足够大,assign 函数也不会重新分配任何东西,正如您所说,您已经通过 reserve 实现了这一点。 是的,我认为 assign 函数完全符合我的需要 - 并且有适当的逻辑来确保我移动的大小永远不会超过我最初保留的大小,所以我不认为它会导致任何分配发生【参考方案2】:

您需要在memmove() 之前调用resize(),而不是之后。

试试这个:

// Move num_bytes from pos_ in currentVector to [0] in otherBuffer
if (num_bytes)                                               
   otherBuffer().resize(num_bytes);                                     
   memmove(&(otherBuffer()[0]), &((*bytes)[pos_]), num_bytes);
                                                             

【讨论】:

当然,您应该做的就是删除所有这些代码并用otherBuffer().assign(...)替换它。

以上是关于在缓冲区之间移动字节时出现意外结果的主要内容,如果未能解决你的问题,请参考以下文章

为啥缓冲区未满时字节缓冲区会出现缓冲区溢出异常

java IO和NIO区别

eventbuffer 在输入时只能读取 8 个字节?

从套接字读取时出现意外行为

无法在具有307200字节的TensorFlowLite缓冲区和具有270000字节的Java缓冲区之间转换

SWIG:numpy 包装器的意外结果?