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 本质是"固定容量对象池 + 环形队列",

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

相关推荐
Darkwanderor23 分钟前
对Linux的进程控制的研究
linux·运维·c++
云泽8081 小时前
从零吃透 C++ 异常:抛出捕获、栈展开、异常重抛与编码规范详解
开发语言·c++·代码规范
轻颂呀1 小时前
约瑟夫环问题
算法
REDcker1 小时前
libdatachannel 快速入门
c++·webrtc·datachannel
科技大视界3 小时前
投资AI项目,传统尽调不够用了——李章虎律师拆解算法、数据、算力三大雷区
人工智能·算法·数据挖掘
second603 小时前
第一部分:快速上手 —— 建立 C++ 基本语法与编程范式
开发语言·c++
郝学胜-神的一滴3 小时前
算法实战:最小k个数——大顶堆的优雅解法
开发语言·数据结构·c++·python·程序人生·算法·排序算法
Irissgwe3 小时前
算法滑动窗口
数据结构·算法
bksczm3 小时前
linux之线程概念和控制
linux·开发语言·c++
怪兽学LLM3 小时前
LeetCode 105. 从前序与中序遍历序列构造二叉树:分治递归思路详解
算法·leetcode·职场和发展