請在提交支持請求之前仔細閱讀此讀書我,並檢查以前回答的問題之間是否已經存在答案:請勿濫用GitHub問題跟踪器。
根據我的計算,該庫本身的內存消耗約為0.5kb :580字節(最大)和8個字節。顯然,這並不考慮用於存儲物品本身的空間。
聲明緩衝區時,應指定必須處理的數據類型和緩衝區容量:這兩個參數將影響緩衝區消耗的內存。
# include < CircularBuffer.hpp >
CircularBuffer<byte, 100 > bytes; // uses 538 bytes
CircularBuffer< int , 100 > ints; // uses 638 bytes
CircularBuffer< long , 100 > longs; // uses 838 bytes
CircularBuffer< float , 100 > floats; // uses 988 bytes
CircularBuffer< double , 100 > doubles; // uses 988 bytes
CircularBuffer< char , 100 > chars; // uses 538 bytes
CircularBuffer< void *, 100 > pointers; // uses 638 bytes
請注意:上面報告的內存使用情況包括圖書館代碼使用的程序內存,堆內存少得多,並且與緩衝區的大小和類型相媲美。
讓我們開始清楚情況:庫不支持在緩衝區中間插入數據。您可以通過unshift()
操作或通過push()
操作將數據添加到第一個元素之前,或者通過unshift()操作添加數據。您可以繼續添加超出緩衝區最大容量的數據,但是您將丟失最不重要的信息:
unshift()
增加了頭部,因此增加容量會導致尾部的元素被覆蓋並丟失push()
增加了尾巴,因此增加容量會導致頭部的元素被覆蓋並丟失如果添加沒有造成任何信息丟失,則unshift()
和push()
返回true
如果發生覆蓋物,則false: false
:
CircularBuffer< int , 5 > buffer; // buffer capacity is 5
// all of the following return true
buffer.unshift( 1 ); // [1]
buffer.unshift( 2 ); // [2,1]
buffer.unshift( 3 ); // [3,2,1]
buffer.push( 0 ); // [3,2,1,0]
buffer.push( 5 ); // [3,2,1,0,5]
// buffer is now at full capacity, from now on any addition returns false
buffer.unshift( 2 ); // [2,3,2,1,0] returns false
buffer.unshift( 10 ); // [10,2,3,2,1] returns false
buffer.push(- 5 ); // [2,3,2,1,-5] returns false
與數據添加類似,可以通過pop()
操作在尾部或通過shift()
操作從頭部執行數據檢索:兩者都會導致讀取的元素從緩衝區中刪除。
在實際緩衝區大小之外的讀取數據具有不確定的行為,並且是用戶有責任使用下一節中列出的其他操作來防止這種邊界違規行為。根據數據類型和分配方法,庫的行為會有所不同,但是如果您不觀看步驟,則可以安全地假設您的程序將崩潰。
也可以使用非破壞性的閱讀操作:
first()
返回元素頭部last()
返回尾部的元素[]
運算符讀取緩衝區中的任何元素CircularBuffer< char , 50 > buffer; // ['a','b','c','d','e','f','g']
buffer.first(); // ['a','b','c','d','e','f','g'] returns 'a'
buffer.last(); // ['a','b','c','d','e','f','g'] returns 'g'
buffer.pop(); // ['a','b','c','d','e','f'] returns 'g'
buffer.pop(); // ['a','b','c','d','e'] returns 'f'
buffer.shift(); // ['b','c','d','e'] returns 'a'
buffer.shift(); // ['c','d','e'] returns 'b'
buffer[ 0 ]; // ['c','d','e'] returns 'c'
buffer[ 1 ]; // ['c','d','e'] returns 'd'
buffer[ 2 ]; // ['c','d','e'] returns 'e'
buffer[ 10 ]; // ['c','d','e'] returned value is unpredictable
buffer[ 15 ]; // ['c','d','e'] returned value is unpredictable
isEmpty()
才返回true
true
isFull()
/數據丟失的情況下無法將數據進一步添加到緩衝區size()
返回當前存儲在緩衝區中的元素的數量;它應與[]
運算符結合使用以避免邊界違規:第一個元素索引始終為0
(如果緩衝區不是空),最後一個元素索引始終是size() - 1
available()
返回在飽和緩衝區之前可以添加的元素數量capacity()
返回緩衝區可以存儲的元素的數量,僅在用戶定義時才完整,並且從不更改從1.3.0
刪除,而被讀取的純構件可變capacity
代替clear()
將整個緩衝區重置為其初始狀態(但是請注意,如果您在緩衝區中動態分配的對象,則該對象使用的內存不會發布:迭代緩衝區內容,並將對象相應地釋放到其分配方法))copyToArray(array)
將緩衝區的內容複製到標準數組array
。陣列必須足夠大才能將當前的所有元素保存在緩衝區中。copyToArray(conversionFn, array)
將緩衝區的內容複製到標準數組array
對每個元素上執行功能的內容,通常是類型轉換。陣列必須足夠大才能將當前的所有元素保存在緩衝區中。 從版本1.3.0
開始,庫能夠根據緩衝區容量自動檢測索引的哪些數據類型:
65535
的緩衝區,那麼您的索引將是一個unsigned long
255
的緩衝區的unsigned int
byte
就足夠了此外,您可以將帶有小索引的相同代碼緩衝區和帶有正常索引的緩衝區混合:以前是不可能的。
CircularBuffer< char , 100 > optimizedBuffer; // reduced memory footprint, index type is uint8_t (a.k.a. byte)
CircularBuffer< long , 500 > normalBuffer; // standard memory footprint, index type is unit16_t (a.k.a. unsigned int)
CircularBuffer< int , 66000 > hugeBuffer; // extended memory footprint, index type is unit32_t (a.k.a. unsigned long)
為了獲得上述優化的最大優勢,任何時候都需要參考緩衝區索引,您應該使用最合適的類型:使用decltype
指示符可以輕鬆實現這一點,例如以下示例:
// the iterator variable i is of the correct type, even if
// we don't know what's the buffer declared capacity
for (decltype(buffer):: index_t i = 0 ; i < buffer.size(); i++) {
avg += buffer[i] / buffer. size ();
}
如果您願意,您可以別名索引類型並參考這樣的別名:
using index_t = decltype(buffer):: index_t ;
for ( index_t i = 0 ; i < buffer.size(); i++) {
avg += buffer[i] / buffer. size ();
}
以下僅適用於1.3.0
之前的版本。
默認情況下,庫使用unsigned int
索引,最多可容納65535
個項目,但是您很少需要如此龐大的商店。
您可以在#include
指令之前將庫索引切換到定義CIRCULAR_BUFFER_XS
acro的byte
類型:這將庫本身使用的內存減少36
字節,但允許您在執行索引的訪問時可能會擠出更多,如果您可以使用較小的數據類型來完成任何操作。
# define CIRCULAR_BUFFER_XS
# include < CircularBuffer.h >
CircularBuffer< short , 100 > buffer;
void setup () { }
void loop () {
// here i should be declared of type byte rather than unsigned int
// in order to maximize the effects of the optimization
for (byte i = 0 ; i < buffer. size () - 1 ; i++) {
Serial. print (buffer[i]);
}
}
請注意:此宏開關迫使緩衝區使用8位數據類型作為內部索引,因為所有緩衝區都將限於最大容量255
。
該庫的確有助於與定義CIRCULAR_BUFFER_INT_SAFE
宏開關的中斷合作,該開關將volatile
修飾符引入count
變量,從而使整個庫以禁用某些編譯器優化的價格更加友好。 #define
語句需要在#include
語句之前放置在某個地方:
# define CIRCULAR_BUFFER_INT_SAFE
# include < CircularBuffer.h >
CircularBuffer< unsigned long , 10 > timings;
void count () {
timings. push ( millis ());
}
void setup () {
attachInterrupt ( digitalPinToInterrupt ( 2 ), count, RISING);
}
void loop () {
Serial. print ( " buffer size is " ); Serial. println (timings. size ());
delay ( 250 );
}
請注意,這並不能使圖書館中斷安全,但確實有助於其在中斷驅動的公司中使用。
庫的examples
夾中有多個示例:
copyToArray()
函數的使用。 如果您使用此庫來存儲動態分配的對象,請不要使用clear()
方法,因為不會執行內存DealLocation:您需要迭代緩衝區內容並相應地將內存發佈到使用的分配方法,要么通過delete
(如果您已經使用了new
)或free
(在malloc
的情況下):
while (!buffer.isEmpty()) {
// pick the correct one
delete buffer. pop ();
free (buffer. pop ());
}
同樣適用於pop()
和shift()
操作,因為任何動態分配的對象僅與緩衝區分離,但是它使用的內存並未自動釋放(請參見Object.ino示例)
Record* record = new Record(millis(), sample); // a dynamically allocated object
buffer.push(record);
// somewhere else
if (!buffer.isEmpty()) {
Record* current = buffer. pop ();
Serial. println (current. value ());
delete current; // if you don't do this the object memory is lost!!!
}
copyToArray(array)
和copyToArray(array, convertFn)
.hpp
.h
標頭擴展名來添加與nano 33 ble的兼容性shift()
和pop()
操作濫用以弄亂緩衝區[]
運算符,以防止邊界訪問abort()
是特定於AVR的以下大多數主要改進是由Erlkoenig90貢獻的:謝謝Niklas!
capacity()
有利於恆定實例屬性capacity
EventLogging
和Interrupts
示例CIRCULAT_BUFFER_XS
宏開關以支持自動索引類型標識UINT32_MAX
)CIRCULAR_BUFFER_INT_SAFE
memset
clear()
函數pop()
函數pop()
和shift()
實現capacity()
函數debug()
函數,默認情況下處理前處理器禁用