C++ 固定容量环形队列实现

1. 适用场景

这种写法适合高频数据流(如视频帧、传感器数据):

  • 需要固定内存上限,避免队列无限增长
  • 希望减少频繁 new/delete 带来的抖动
  • 允许拥塞时丢帧(例如"丢旧保新"以降低时延)

2. 核心思路

底层用固定长度 vector<unique_ptr<T>> 作为槽位池,再配合三个状态量:

  • head:下次入队写入位置(写指针)
  • tail:下次出队读取位置(读指针)
  • size:当前有效元素数量

"环形"靠取模实现:

idx = (idx + 1) % capacity

这样索引走到末尾会回到 0,不需要搬移元素。


3. 两种满队列策略

A. 满了丢新(Reject-New)

  • 队列满时直接返回失败
  • 不覆盖队列中已有数据
  • 简单直观,但可能导致"新数据进不来"

B. 满了丢旧(Keep-Latest)

  • 队列满时仍接收新数据
  • 通过前移 tail 丢弃最老元素
  • 更适合实时场景,减少处理过期数据的概率

4. 简化示例(独立可编译)

cpp 复制代码
#include <iostream>
#include <memory>
#include <vector>

struct Frame {
  int id = -1;
};

class RingQueue {
 public:
  explicit RingQueue(size_t capacity) : buf_(capacity), capacity_(capacity) {
    for (size_t i = 0; i < capacity_; ++i) {
      buf_[i] = std::make_unique<Frame>();  // 预分配槽位对象
    }
  }

  // 满了丢新
  bool PushRejectNew(std::unique_ptr<Frame>& in) {
    if (size_ >= capacity_) return false;
    std::swap(buf_[head_], in);             // O(1) 交换所有权
    head_ = (head_ + 1) % capacity_;
    ++size_;
    return true;
  }

  // 满了丢旧,保留最新
  bool PushKeepLatest(std::unique_ptr<Frame>& in, bool* overwrote_oldest = nullptr) {
    bool overwritten = false;
    std::swap(buf_[head_], in);
    head_ = (head_ + 1) % capacity_;

    if (size_ >= capacity_) {
      tail_ = (tail_ + 1) % capacity_;      // 丢最老元素
      overwritten = true;
    } else {
      ++size_;
    }

    if (overwrote_oldest) *overwrote_oldest = overwritten;
    return true;
  }

  bool Pop(std::unique_ptr<Frame>& out) {
    if (size_ == 0) return false;
    std::swap(buf_[tail_], out);
    tail_ = (tail_ + 1) % capacity_;
    --size_;
    return true;
  }

 private:
  std::vector<std::unique_ptr<Frame>> buf_;
  size_t capacity_{0};
  size_t head_{0};
  size_t tail_{0};
  size_t size_{0};
};

5. 为什么 swap 能提效

  • 不做大对象拷贝,只交换 unique_ptr 所有权
  • 减少动态分配/释放次数,降低内存碎片风险
  • 延迟抖动更小,实时性更稳定

6. 实战注意点

  • 多线程场景必须加锁(或使用无锁结构)
  • 队列容量过小会导致覆盖/丢帧频繁
  • 建议监控:队列长度、覆盖次数、端到端时延

7. 一句话总结

vector + 环形索引 + swap 本质是"固定容量对象池 + 环形队列",

在实时系统中通常比通用动态队列更可控、更稳定。

相关推荐
kisshyshy13 小时前
🍦 雪糕、食堂、火车厢:三幅漫画吃透栈、队列与链表
javascript·算法
众少成多积小致巨15 小时前
JNI (Java Native Interface) 技术手册中文参考指南
android·java·c++
猿人谷20 小时前
不只是 CPU 阈值:STAR 如何用 GAT + Transformer 做容器级自动扩缩容?
人工智能·算法
复杂网络21 小时前
Stable Diffusion 视觉大模型微调技术深度调研
算法
复杂网络21 小时前
基于 Stable Diffusion 架构的视觉大模型代表性工作与原理深度解析
算法
MrZhao4001 天前
Agent Loop 如何用 Hook 扩展:权限、日志与工具拦截
算法
MrZhao4001 天前
Agent 为什么需要 Skills:别把所有知识都塞进 system prompt
算法
JieE2122 天前
LeetCode 101. 对称二叉树|JS 递归 + 迭代双解法,彻底搞懂镜像判断
javascript·算法
JieE2123 天前
LeetCode 56. 合并区间|超清晰 JS 图解思路,面试高频区间题
javascript·算法·面试
Jack204 天前
HarmonyOS开发中错误处理策略:网络异常统一处理
算法