我应该使用哪一个STL容器作为FIFO?
哪个STL容器最适合我的需求? 我基本上有一个10个元素的容器,在这个容器中我不断push_back
新元素,同时pop_front
最老的元素(大约一百万次)。
我目前正在使用一个std::deque
的任务,但想知道如果一个std::list
将更有效,因为我不需要重新分配自己(或者我误解std::deque
std::vector
?)。 还是有一个更有效的容器,我的需要?
PS我不需要随机访问
既然有无数的答案,你可能会感到困惑,但总结一下:
使用一个std::queue
。 原因很简单:它是一个FIFO结构。 你想要FIFO,你使用一个std::queue
。
它使你的意图清楚,任何人,甚至你自己。 std::list
或std::deque
不。 一个列表可以在任何地方插入和删除,这不是FIFO结构所要做的,而且可以从任一端添加和删除,这也是FIFO结构无法做到的。
这就是为什么你应该使用queue
。
现在,你问了关于performance。 首先,永远记住这个重要的经验法则: 优先代码,性能最后。
其原因很简单:在清洁和优雅之前努力performance的人们几乎总是最后完成。 他们的代码变成了一团糟,因为他们已经放弃了所有的好东西,为的是什么都不做。
通过首先编写好的可读代码,大部分性能问题都将自行解决。 如果后来你发现自己的性能不足,现在很容易在你的漂亮,干净的代码中添加一个分析器,并找出问题出在哪里。
这一切都表示, std::queue
只是一个适配器。 它提供了安全的接口,但在内部使用了不同的容器。 你可以select这个底层容器,这样可以有很大的灵活性。
那么,你应该使用哪个底层容器呢? 我们知道std::list
和std::deque
都提供了必要的函数( push_back()
, pop_front()
和front()
),所以我们如何决定呢?
首先,明白分配(和释放)内存通常不是一件快事,因为它涉及到操作系统并要求它做某事。 list
必须在每次添加内容时分配内存,并在内存消失时释放内存。
另一方面, deque
大块分配。 它将分配的次数less于list
。 把它想象成一个列表,但是每个内存块可以容纳多个节点。 (当然,我build议你真的了解它是如何工作的 。)
所以,只有这样一个deque
才能performance得更好,因为它并不像往常那样处理记忆。 事实上,你处理的是大小不等的数据,在第一次通过数据之后可能不需要分配数据,而列表将不断地分配和释放。
要理解的第二件事是caching性能 。 出门到内存很慢,所以当CPU真正需要的时候,通过把一块内存带回到caching中,这个时间是最好的。 因为deque
在内存块中分配,访问这个容器中的一个元素很可能会导致CPU将容器的其余部分也带回来。 现在,任何进一步的访问将会很快,因为数据在caching中。
这不同于一次一个分配数据的列表。 这意味着数据可能遍布在内存中,并且caching性能会变差。
所以,考虑到这一点,一个deque
应该是一个更好的select。 这就是为什么它是使用queue
时的默认容器。 所有人都说,这仍然只是一个(非常)教育的猜测:你将不得不分析这个代码,在一个testing中使用deque
在另一个testing中list
一个真正的确定。
但请记住:让代码使用干净的界面,然后担心性能。
约翰提出了一个担心,即包装list
或deque
会导致业绩下降。 再一次,如果不自己分析,我也不能肯定地说,但是编译器会插入queue
调用的机会。 也就是说,当你说queue.push()
,它真的只是说queue.container.push_back()
,完全跳过函数调用。
再一次,这只是一个受过教育的猜测,但使用queue
不会降低性能,与使用底层容器原始数据相比。 就像我以前说过的那样,使用queue
,因为它干净,易用,安全,如果真的成为问题configuration文件和testing。
退房std ::队列。 它包装一个底层的容器types,默认的容器是std :: deque。
在性能真正重要的地方,请查看Boost循环缓冲区库 。
我不断
push_back
新元素,而pop_front
最老的元素(大约一百万次)。
一百万人在计算方面真的不是很多。 正如其他人所build议的,使用std::queue
作为您的第一个解决scheme。 在不太可能发生的情况下,使用探查器识别瓶颈(不要猜测!),并使用具有相同接口的不同容器重新实现。
为什么不std::queue
? 它只有push_back
和pop_front
。
一个队列可能是一个比deque更简单的接口,但是对于这样一个小列表来说,性能的差别可能是微不足道的。
列表也一样 。 只需要select你想要的API。