循环缓冲区实现

时间:2016-08-10 14:45:18

标签: c++ algorithm circular-buffer

是的,我再来一次非常直接的实现,就像这样:

    // write data always! if buffer is already full, overwrite old data!
    void Put( const CONTENT_TYPE &data )
    {
        buffer[ inOffset++] = data;
        inOffset%=size;

        // was data overwritten, skip it by increment read offset
        if ( inOffset == outOffset ) 
        {
            outOffset++;
            outOffset%=size;
            std::cout << "Overwrite" << std::endl;
        }
    }

    CONTENT_TYPE Pull()
    {
        CONTENT_TYPE data = buffer[ outOffset++ ];
        outOffset %= size;
        return data;
    }

但是这个简单的算法只使用缓冲区的1个大小的元素!

如果我想避免这种情况,我只找到一个添加另一个计数器变量的解决方案,这会浪费我sizeof(counter_var) - sizeof(element)bytes。

问:有没有浪费记忆的解决方案?它看起来很简单,但我无法理解: - )

备注:还有一些代码行可以保护空读和其他内容,但这对于这个问题并不重要。并且它没有标记c ++,因为算法不依赖于语言,如果我给出一个c ++代码示例。

3 个答案:

答案 0 :(得分:1)

如果一个是索引而另一个是元素计数,则可以使用两个整数并填充所有插槽,然后转换为动态查找第二个索引:

void put(const ELEMENT& element) {
  if (nElements == size) throw "put: buffer full";
  buffer[(start + nElements++) % size] = element;
}

ELEMENT get() {
  if (nElements == 0) throw "get: buffer empty";
  ELEMENT& value = buffer[start];
  start = (start + 1) % size;
  --nElements;
  return value;
}

当然,如果您愿意,可以用if (foo > size) foo -= size;替换mod操作。

答案 1 :(得分:0)

您只需使用不同的时间点来处理模数运算;假设我们在每次访问后增加读写指针。如果我们现在在增加后立即执行读指针的模数,并且在读取之前写指针的模数正好,则| write-read |完整缓冲区的长度是缓冲区的长度,没有任何特殊情况处理。为了实现这一点,您的写指针应始终使用 % buffer_length,但存储 % (2 * buffer_length)

我并不特别喜欢马克的答案,因为将事物作为特殊情况处理通常不是一个好主意,因为引入负哨点值就像你通常使用size_t的地方一样(即无符号整数)。

答案 2 :(得分:-1)

您可以为其中一个偏移使用特殊的sentinel值,例如-1,以指示缓冲区已满或为空。这将使您的代码复杂化,以检查和修改偏移量。

// write data always! if buffer is already full, overwrite old data!
void Put( const CONTENT_TYPE &data )
{
    buffer[ inOffset++] = data;
    inOffset%=size;

    // was data overwritten, skip it by setting read offset to sentinel
    if ( inOffset == outOffset || outOffset == -1 ) 
    {
        outOffset = -1;
        std::cout << "Overwrite" << std::endl;
    }
}

CONTENT_TYPE Pull()
{
    if (outOffset == -1)
        outOffset = inOffset;
    CONTENT_TYPE data = buffer[ outOffset++ ];
    outOffset %= size;
    return data;
}

bool IsEmpty()
{
    return outOffset == inOffset;
}