C++ 我应该使用哪个STL容器作为FIFO?

C++ 我应该使用哪个STL容器作为FIFO?,c++,stl,fifo,C++,Stl,Fifo,哪个STL容器最适合我的需要?我基本上有一个10个元素宽的容器,在这个容器中我不断地向后推新元素,同时向前推最古老的元素(大约一百万次) 我目前正在使用std::deque来完成任务,但我想知道std::list是否会更有效,因为我不需要重新分配它自己(或者我可能把std::deque误认为是std::vector?)。还是有更有效的容器满足我的需要 另外,我不需要随机访问A可能比A更简单,但对于这样一个小列表,性能上的差异可能可以忽略不计 同样的情况也会发生。这取决于您想要什么API。请查看s

哪个STL容器最适合我的需要?我基本上有一个10个元素宽的容器,在这个容器中我不断地向后推新元素,同时向前推最古老的元素(大约一百万次)

我目前正在使用
std::deque
来完成任务,但我想知道
std::list
是否会更有效,因为我不需要重新分配它自己(或者我可能把
std::deque
误认为是
std::vector
?)。还是有更有效的容器满足我的需要

另外,我不需要随机访问

A可能比A更简单,但对于这样一个小列表,性能上的差异可能可以忽略不计


同样的情况也会发生。这取决于您想要什么API。

请查看
std::queue
。它包装一个底层容器类型,默认容器是
std::deque

为什么不
std::queue
?它所能做的就是
向后推
向前推

我不断地
推回
新元素
而
pop_front
ing最旧的元素 (大约一百万次)


在计算机领域,一百万真的不是一个大数字。正如其他人所建议的,使用
std::queue
作为第一个解决方案。如果速度太慢,请使用探查器(不要猜测!)确定瓶颈,并使用具有相同接口的不同容器重新实现。

由于答案很多,您可能会感到困惑,但总结一下:

使用一个。原因很简单:它是FIFO结构。如果需要FIFO,可以使用
std::queue

这会让别人,甚至你自己都清楚你的意图。A或不。列表可以在任何地方插入和删除,这不是FIFO结构应该做的,而
deque
可以在任意一端添加和删除,这也是FIFO结构不能做的

这就是为什么您应该使用
队列


现在,你问了关于性能的问题。首先,请始终记住这条重要的经验法则:先编写好代码,后执行性能。

原因很简单:在追求清洁和优雅之前追求表现的人几乎总是最后完成。他们的代码变得乱七八糟,因为他们放弃了一切好的东西,只是为了真正从中一无所获

通过先编写好的、可读的代码,大多数性能问题都会自行解决。如果以后发现性能不足,现在可以很容易地在漂亮、干净的代码中添加分析器,并找出问题所在

总之,
std::queue
只是一个适配器。它提供了安全接口,但在内部使用了不同的容器。您可以选择这个底层容器,这允许很大的灵活性

那么,您应该使用哪个底层容器呢?我们知道
std::list
std::deque
都提供了必要的功能(
push_-back()
pop_-front()
)和
front()
),那么我们如何决定呢

首先,要明白分配(和取消分配)内存通常不是一件容易的事情,因为它涉及到操作系统并要求它做一些事情。
列表
必须在每次添加某个内容时分配内存,并在该内容消失时取消分配

另一方面,
deque
,以块的形式进行分配。它的分配频率将低于
列表
。可以将其视为一个列表,但每个内存块可以容纳多个节点。(当然,我建议你。)

因此,仅凭这一点,
deque
就应该表现得更好,因为它不经常处理内存。再加上您正在处理的数据大小不变,在第一次传递数据之后,它可能不必进行分配,而列表将不断地进行分配和解除分配

第二件需要理解的事情是。进入RAM的速度很慢,所以当CPU真的需要时,它会充分利用这段时间,将一大块内存带回到缓存中。由于
deque
在内存中分配块,因此访问此容器中的元素很可能会导致CPU返回容器的其余部分。现在,对
deque
的任何进一步访问都会很快,因为数据在缓存中

这与列表不同,列表中的数据一次分配一个。这意味着数据可能分布在内存中的所有位置,缓存性能将很差

因此,考虑到这一点,一个
deque
应该是一个更好的选择。这就是为什么在使用
队列时它是默认容器的原因。尽管如此,这仍然只是一个(非常)有教育意义的猜测:你必须分析这段代码,在一个测试中使用
deque
,在另一个测试中使用
list
,才能真正确定

但请记住:让代码使用干净的界面,然后再担心性能

John提出了一个问题,即包装
列表
deque将导致性能下降。再一次,他和我都可以肯定地说,不需要自己分析它,但编译器很可能会内联
队列
发出的调用。也就是说,当您说
queue.push()
,它实际上只会说
queue.container.push\u back()
,完全跳过函数调用


同样,这只是一个有根据的猜测,但是与使用底层容器raw相比,使用
队列将不会降低性能。正如我之前所说,使用
队列
,因为它干净、易于使用且安全,如果它真的成为一个问题配置文件和测试。

在性能真正重要的地方,请查看。

使用
标准::队列
,但要注意
// FIFO with circular buffer
#define fifo_size 4

class Fifo {
  uint8_t buff[fifo_size];
  int writePtr = 0;
  int readPtr = 0;
  
public:  
  void put(uint8_t val) {
    buff[writePtr%fifo_size] = val;
    writePtr++;
  }
  uint8_t get() {
    uint8_t val = NULL;
    if(readPtr < writePtr) {
      val = buff[readPtr%fifo_size];
      readPtr++;
      
      // reset pointers to avoid overflow
      if(readPtr > fifo_size) {
        writePtr = writePtr%fifo_size;
        readPtr = readPtr%fifo_size;
      }
    }
    return val;
  }
  int count() { return (writePtr - readPtr);}
};