环形缓冲区使用固定数组和头尾指针实现FIFO,通过取模运算形成循环,利用full标志区分满/空状态,支持高效读写操作,适用于生产者-消费者等场景。

环形缓冲区(Ring Buffer),也叫循环队列,是一种固定大小的先进先出(FIFO)数据结构,常用于生产者-消费者场景、串口通信、音频处理等。C++ 中实现环形缓冲区可以通过数组加头尾指针的方式高效完成。
基本原理
环形缓冲区使用一个固定大小的数组,并维护两个索引:- head:指向下一个写入位置
- tail:指向下一个读取位置
简单模板实现
下面是一个线程不安全但高效的环形缓冲区模板实现:
template <typename T, size_t N>
class RingBuffer {
private:
T buffer[N];
size_t head = 0;
size_t tail = 0;
bool full = false;
<p>public:
// 判断是否为空
bool empty() const {
return !full && (head == tail);
}</p><pre class='brush:php;toolbar:false;'>// 判断是否已满
bool full() const {
return full;
}
// 写入一个元素
bool push(const T& item) {
if (full) return false;
buffer[head] = item;
head = (head + 1) % N;
if (head == tail) {
full = true;
}
return true;
}
// 读取一个元素
bool pop(T& item) {
if (empty()) return false;
item = buffer[tail];
tail = (tail + 1) % N;
full = false;
return true;
}
// 返回当前元素数量
size_t size() const {
if (full) return N;
return (head >= tail) ? (head - tail) : (N - tail + head);
}};
使用示例
你可以这样使用这个环形缓冲区:
#include <iostream>
<p>int main() {
RingBuffer<int, 4> rb;</p><pre class='brush:php;toolbar:false;'>rb.push(1);
rb.push(2);
rb.push(3);
int val;
while (rb.pop(val)) {
std::cout << val << " ";
}
// 输出:1 2 3
return 0;}
立即学习“C++免费学习笔记(深入)”;
关键细节说明
实现环形缓冲区时要注意以下几点:-
满/空判断:头尾相等时可能为空也可能为满,这里用一个额外的
full标志区分 -
取模运算:使用
% N实现索引回绕,注意性能(可对 2 的幂用位运算优化) - 线程安全:上述实现非线程安全,多线程环境下需加锁或使用原子操作
- 异常安全:拷贝构造和赋值操作要考虑异常安全性,必要时使用 RAII
如果需要线程安全版本,可以加上互斥锁:
#include <mutex>
<p>// 在类中添加:
mutable std::mutex mtx;</p><p>bool push(const T& item) {
std::lock_guard<std::mutex> lock(mtx);
// 原逻辑...
}</p>基本上就这些。环形缓冲区实现不复杂但容易忽略边界条件,关键是处理好满/空状态和索引回绕。











