[英]circular buffer implementation
再次是,我再次提出了非常簡單的實現,如下所示:
// 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)個字節。
問:有沒有不浪費內存的解決方案? 它看起來很簡單,但我抓不到:-)
備注:還有更多的代碼行可以保護空讀取和其他內容,但這對這個問題並不重要。 而且它沒有被標記為c ++,因為該算法不依賴於語言,即使我舉一個c ++代碼示例也是如此。
您可以使用兩個整數並填充所有插槽(如果一個是索引,另一個是元素計數),然后立即進行轉換以找到第二個索引:
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操作if (foo > size) foo -= size;
如果你喜歡。
您可以通過使用不同的時間點進行模運算來解決這個問題。 假設我們在每次訪問后都增加了讀寫指針。 如果現在我們在增加之后立即執行讀指針的模,而就在讀之前立即寫寫指針的模,則| write-read | 完整緩沖區的長度將是緩沖區的長度,無需任何特殊情況處理。 為此,您的寫指針應始終使用 % buffer_length
,但應存儲 % (2 * buffer_length)
。
我不特別喜歡Mark的答案,因為按特殊情況處理事物通常不是一個好主意,在您通常使用size_t
(即無符號整數)的地方,引入負的前哨值就少了。
您可以對偏移量之一使用特殊的前哨值,例如-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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.