我正在尝试实现一个非常简单的环形缓冲区,用于以浮点值的形式保存音频样本流。
我希望能够在任何时候拍摄音频输入的快照。我不需要弹出或删除任何值,只需保留最后 n 样本的移动缓冲区。
我想问一下这个实现是否存在任何潜在的问题。
class RingBuffer
{
public:
RingBuffer (int bufferSize) : bufferSize (bufferSize), count (0), head (0)
{
buffer = static_cast<float *> (malloc(bufferSize * sizeof(float)));
readBuffer = static_cast<float *> (malloc(bufferSize * sizeof(float)));
}
~RingBuffer ()
{
if (buffer != nullptr) free(buffer);
buffer = nullptr;
if (readBuffer != nullptr) free(readBuffer);
readBuffer = nullptr;
}
void push (float value)
{
if (count < bufferSize && head == 0)
{
buffer[count++] = value;
}
else if (count == bufferSize)
{
// reset head to beginning if reached the end
if (head >= bufferSize)
{
head = 0;
buffer[head] = value;
}
else
{
buffer[head++] = value;
}
}
}
/**
* Return a snapshot of the buffer as a continous array
*/
const float* getSnapshot ()
{
// Set up read buffer as continuous stream
int writeIndex = 0;
for (int i = head; i < count; ++i)
{
readBuffer[writeIndex++] = buffer[i];
}
for (int i = 0; i < head; ++i)
{
readBuffer[writeIndex++] = buffer[i];
}
return readBuffer;
}
private:
int bufferSize, head, count;
float* buffer;
float* readBuffer;
};
答案 0 :(得分:2)
嗯,我确实可以看到几个问题。抱歉,这是个坏消息: - /
错误
buffer[head] = value;
。您不会增加head
,因此当下一个样本进入时,此位置的样本将会丢失(覆盖)。buffer
和readBuffer
初始化为nullptr
:如果您的某个malloc失败,您的析构函数将尝试释放getSnapshot
中的第一个循环有问题:终点应该是min(bufferSize,head+count)
而不是count
设计问题
new float[bufferSize]
分配数组,它比mallocs更简单,更易读std::unique_ptr
保留每个缓冲区,这样您就不再需要任何析构函数(并且您的代码会更安全)writeIndex = (writeIndex +1 ) % bufferSize
。您的代码将更加简单,特别是在getSnapshot(一个循环而不是两个循环)