不能直接用std::queue,因其底层std::deque内存不连续、扩容realloc、有指针开销;循环队列需固定内存零拷贝,标准解法牺牲一个槽位,用front==rear判空、(rear+1)%capacity==front判满,优先std::array而非vector,多线程需加锁或原子操作。

为什么不能直接用 std::queue?
因为循环队列的核心诉求是「固定内存 + 零拷贝复用」,比如嵌入式缓冲、高频日志暂存、实时音频流处理——std::queue 底层默认用 std::deque,内存不连续,扩容会 realloc,还带额外指针开销。真要压测或跑在资源受限设备上,得自己控数组边界。
front 和 rear 怎么算下标才不越界?
别用 (i + 1) % capacity 硬套——容易漏掉「空/满判定冲突」这个坑。标准解法是**牺牲一个槽位**:队列最多存 capacity - 1 个元素,靠 front == rear 判空,(rear + 1) % capacity == front 判满。
-
push()时先判满,再写入data[rear],然后rear = (rear + 1) % capacity -
pop()时先判空,再读data[front],然后front = (front + 1) % capacity - 注意:
capacity是你分配的数组长度,不是逻辑容量
用 std::array 还是裸 int data[N]?
优先选 std::array<T, N>:它自带 size()、能传参进函数、支持范围 for,且编译期确定大小,和裸数组一样零开销。但别写 std::vector<T>——动态分配破坏循环队列的初衷。
示例关键片段:
立即学习“C++免费学习笔记(深入)”;
template <typename T, size_t N>
class CircularQueue {
std::array<T, N> data;
size_t front = 0;
size_t rear = 0;
static constexpr size_t capacity = N;
<p>public:
bool empty() const { return front == rear; }
bool full() const { return (rear + 1) % capacity == front; }
void push(const T& x) {
if (full()) throw std::runtime_error("queue overflow");
data[rear] = x;
rear = (rear + 1) % capacity;
}
T pop() {
if (empty()) throw std::runtime_error("queue underflow");
T x = data[front];
front = (front + 1) % capacity;
return x;
}
};</p>多线程环境下直接用会崩吗?
会。上述实现完全没加锁,front 和 rear 都是普通变量,两个线程同时 push 可能导致 rear 被覆盖、数据错乱。真要并发,得上原子操作或互斥锁:
- 简单场景:用
std::mutex包住push/pop整个临界区 - 高性能场景:改用
std::atomic_size_t存front/rear,但要注意 ABA 问题,且 CAS 循环得手写校验逻辑 - 更稳的做法:直接换成熟轮子,比如
moodycamel::ConcurrentQueue(无锁),它底层也是循环数组,但已处理好内存序和边界
裸写循环队列最易被忽略的,其实是「判满判空逻辑必须严格匹配,且 capacity 必须比实际需求多一」——少这一步,调试时丢数据根本看不出哪行出的问题。


















