环形缓冲区是固定大小的fifo结构,用取模实现索引回绕;c++中以vector+双索引实现,含push/pop/front等操作,线程不安全需额外同步。

环形缓冲区(Ring Buffer)是一种固定大小的先进先出(FIFO)数据结构,通过首尾相连的数组模拟“循环”行为,避免内存频繁移动。C++中常用 std::vector 或原生数组配合两个索引(读位置 read_idx、写位置 write_idx)实现,关键在于用取模运算处理边界。
基础模板实现(线程不安全,适合单线程场景)
以下是一个轻量、泛型、无锁的环形缓冲区模板类:
#include <vector>
#include <cassert>
<p>template <typename T>
class RingBuffer {
private:
std::vector<T> buffer_;
size<em>t capacity</em>;
size_t read<em>idx</em> = 0;
size_t write<em>idx</em> = 0;
size<em>t size</em> = 0; // 可选:缓存当前元素数量,避免每次计算</p><p>public:
explicit RingBuffer(size<em>t capacity) : capacity</em>(capacity), buffer_(capacity) {}</p><pre class='brush:php;toolbar:false;'>bool empty() const { return size_ == 0; }
bool full() const { return size_ == capacity_; }
size_t size() const { return size_; }
size_t capacity() const { return capacity_; }
// 写入一个元素(失败时返回 false)
bool push(const T& item) {
if (full()) return false;
buffer_[write_idx_] = item;
write_idx_ = (write_idx_ + 1) % capacity_;
++size_;
return true;
}
// 读取并移除一个元素(失败时返回 false)
bool pop(T& item) {
if (empty()) return false;
item = buffer_[read_idx_];
read_idx_ = (read_idx_ + 1) % capacity_;
--size_;
return true;
}
// 查看队首(不移除)
bool front(T& item) const {
if (empty()) return false;
item = buffer_[read_idx_];
return true;
}};
立即学习“C++免费学习笔记(深入)”;
使用示例
快速验证功能是否正常:
#include <iostream>
<p>int main() {
RingBuffer<int> rb(3);</p><pre class='brush:php;toolbar:false;'>rb.push(10); rb.push(20); rb.push(30); // 满了
assert(rb.full());
int x;
rb.pop(x); // x == 10
rb.push(40); // 30 被覆盖?不,此时:[40,20,30],read_idx=1 → 下次 pop 是 20
// 实际顺序:入 10→20→30→40,出 10→20→40(30 还在但已被绕过)
// 环形缓冲区不保证“覆盖最老”,而是按 FIFO 逻辑:新写入总在写指针处,旧数据自然被丢弃仅当缓冲区满且继续 push}
关键细节说明
-
容量与大小分离:构造时指定最大容量;
size_成员让empty()/full()判断 O(1),比每次算(write_idx_ - read_idx_ + capacity_) % capacity_更清晰可靠 - 无需清零内存:只在有效范围内读写,未读数据不关心内容,避免冗余赋值
-
下标更新用取模:
(idx + 1) % capacity_是核心,确保索引自动回绕到 0 -
线程安全需额外保护:多线程读写必须加锁(如
std::mutex),或改用原子操作+内存序(进阶,适用于 lock-free 场景)
可选增强方向
- 支持
push_n/pop_n批量操作(提升吞吐) - 添加
reserve和resize(注意:环形结构 resize 需重新映射数据) - 用
std::array替代vector实现编译期固定大小(零开销) - 为嵌入式场景提供无动态分配版本(传入外部内存块)










