先进先出应该使用哪个STL容器?

时间:2022-12-09 23:33:26

Which STL container would fit my needs best? I basically have a 10 elements wide container in which I continually push_back new elements while pop_front ing the oldest element (about a million time).

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

I am currently using a std::deque for the task but was wondering if a std::list would be more efficient since I wouldn't need to reallocate itself (or maybe I'm mistaking a std::deque for a std::vector?). Or is there an even more efficient container for my need?

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

P.S. I don't need random access

附注:我不需要随机存取

6 个解决方案

#1


156  

Since there are a myriad of answers, you might be confused, but to summarize:

既然有无数的答案,你可能会感到困惑,但总结一下:

Use a std::queue. The reason for this is simple: it is a FIFO structure. You want FIFO, you use a std::queue.

使用std::队列。原因很简单:它是FIFO结构。你想要FIFO,你使用std::queue。

It makes your intent clear to anybody else, and even yourself. A std::list or std::deque does not. A list can insert and remove anywhere, which is not what a FIFO structure is suppose to do, and a deque can add and remove from either end, which is also something a FIFO structure cannot do.

它使你的意图对任何人,甚至你自己清楚。A std::list或std::deque没有。一个列表可以在任何地方插入和删除,这不是FIFO结构应该做的,deque可以从任意一端添加和删除,这也是FIFO结构不能做的。

This is why you should use a queue.

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

Now, you asked about performance. Firstly, always remember this important rule of thumb: Good code first, performance last.

你问的是性能。首先,永远记住这条重要的经验法则:好的代码首先,性能最后。

The reason for this is simple: people who strive for performance before cleanliness and elegance almost always finish last. Their code becomes a slop of mush, because they've abandoned all that is good in order to really get nothing out of it.

原因很简单:在清洁和优雅之前努力工作的人几乎总是能坚持到最后。他们的代码变成了一堆垃圾,因为他们为了什么都得不到而放弃了所有好的东西。

By writing good, readable code first, most of you performance problems will solve themselves. And if later you find your performance is lacking, it's now easy to add a profiler to your nice, clean code, and find out where the problem is.

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

That all said, std::queue is only an adapter. It provides the safe interface, but uses a different container on the inside. You can choose this underlying container, and this allows a good deal of flexibility.

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

So, which underlying container should you use? We know that std::list and std::deque both provide the necessary functions (push_back(), pop_front(), and front()), so how do we decide?

那么,应该使用哪个底层容器呢?我们知道std::list和std::deque都提供了必要的函数(push_back()、pop_front()和front()),那么我们如何决定呢?

First, understand that allocating (and deallocating) memory is not a quick thing to do, generally, because it involves going out to the OS and asking it to do something. A list has to allocate memory every single time something is added, and deallocate it when it goes away.

首先,要明白,一般来说,分配(和释放)内存不是一件容易的事情,因为它涉及到到到操作系统,并要求它做一些事情。一个列表必须在每次添加某个东西时分配内存,并在它离开时释放它。

A deque, on the other hand, allocates in chunks. It will allocate less often than a list. Think of it as a list, but each memory chunk can hold multiple nodes. (Of course, I'd suggest that you really learn how it works.)

另一方面,deque也分配到块中。它会比列表分配得更少。把它看作一个列表,但是每个内存块可以容纳多个节点。(当然,我建议你真正了解它是如何工作的。)

So, with that alone a deque should perform better, because it doesn't deal with memory as often. Mixed with the fact you're handling data of constant size, it probably won't have to allocate after the first pass through the data, whereas a list will be constantly allocating and deallocating.

因此,单就这一点而言,deque应该表现得更好,因为它不经常处理内存。与处理常量大小的数据相混合,在第一次传递数据之后,它可能不需要进行分配,而列表将不断地进行分配和分配。

A second thing to understand is cache performance. Going out to RAM is slow, so when the CPU really needs to, it makes the best out of this time by taking a chunk of memory back with it, into cache. Because a deque allocates in memory chunks, it's likely that accessing an element in this container will cause the CPU to bring back the rest of the container as well. Now any further accesses to the deque will be speedy, because the data is in cache.

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

This is unlike a list, where the data is allocated one at a time. This means that data could be spread out all over the place in memory, and cache performance will be bad.

这与列表不同,在列表中每次分配一个数据。这意味着数据可以在内存中到处分布,缓存性能将会很差。

So, considering that, a deque should be a better choice. This is why it is the default container when using a queue. That all said, this is still only a (very) educated guess: you'll have to profile this code, using a deque in one test and list in the other to really know for certain.

因此,考虑到这一点,deque应该是更好的选择。这就是为什么在使用队列时它是默认的容器。所有这些都说明,这仍然只是一个(非常)有根据的猜测:您必须对这段代码进行概要分析,在一个测试中使用deque,在另一个测试中使用list,才能真正确定。

But remember: get the code working with a clean interface, then worry about performance.

但是请记住:让代码使用干净的接口,然后考虑性能。

John raises the concern that wrapping a list or deque will cause a performance decrease. Once again, he nor I can say for certain without profiling it ourselves, but chances are that the compiler will inline the calls that the queue makes. That is, when you say queue.push(), it will really just say queue.container.push_back(), skipping the function call completely.

John担心包装列表或deque会导致性能下降。同样,他和我都可以肯定地说,而不必自己分析它,但是编译器很可能会内联队列发出的调用。也就是说,当您说queue.push()时,它实际上只会说queue.container.push_back(),完全跳过函数调用。

Once again, this is only an educated guess, but using a queue will not degrade performance, when compared to using the underlying container raw. Like I've said before, use the queue, because it's clean, easy to use, and safe, and if it really becomes a problem profile and test.

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

#2


26  

Check out std::queue. It wraps an underlying container type, and the default container is std::deque.

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

#3


10  

Where performance really matters, check out the Boost circular buffer library.

如果性能真的很重要,请查看Boost循环缓冲区库。

#4


6  

I continually push_back new elements while pop_front ing the oldest element (about a million time).

我不断地使用push_back新元素,而pop_front是最古老的元素(大约一百万次)。

A million is really not a big number in computing. As others have suggested, use a std::queue as your first solution. In the unlikely event of it being too slow, identify the bottleneck using a profiler (do not guess!) and re-implement using a different container with the same interface.

一百万在计算中并不是一个很大的数字。正如其他人所建议的,使用std::queue作为您的第一个解决方案。在不太可能出现的情况下,使用分析器(不要猜测!)识别瓶颈,并使用具有相同接口的不同容器重新实现。

#5


5  

Why not std::queue? All it has is push_back and pop_front.

为什么不std::队列?它只有push_back和pop_front。

#6


3  

A queue is probably a simpler interface than a deque but for such a small list, the difference in performance is probably negligible.

队列可能是比deque更简单的接口,但对于如此小的列表,性能上的差异可能可以忽略不计。

Same goes for list. It's just down to a choice of what API you want.

同样适用于列表。这取决于你想要什么API。

#1


156  

Since there are a myriad of answers, you might be confused, but to summarize:

既然有无数的答案,你可能会感到困惑,但总结一下:

Use a std::queue. The reason for this is simple: it is a FIFO structure. You want FIFO, you use a std::queue.

使用std::队列。原因很简单:它是FIFO结构。你想要FIFO,你使用std::queue。

It makes your intent clear to anybody else, and even yourself. A std::list or std::deque does not. A list can insert and remove anywhere, which is not what a FIFO structure is suppose to do, and a deque can add and remove from either end, which is also something a FIFO structure cannot do.

它使你的意图对任何人,甚至你自己清楚。A std::list或std::deque没有。一个列表可以在任何地方插入和删除,这不是FIFO结构应该做的,deque可以从任意一端添加和删除,这也是FIFO结构不能做的。

This is why you should use a queue.

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

Now, you asked about performance. Firstly, always remember this important rule of thumb: Good code first, performance last.

你问的是性能。首先,永远记住这条重要的经验法则:好的代码首先,性能最后。

The reason for this is simple: people who strive for performance before cleanliness and elegance almost always finish last. Their code becomes a slop of mush, because they've abandoned all that is good in order to really get nothing out of it.

原因很简单:在清洁和优雅之前努力工作的人几乎总是能坚持到最后。他们的代码变成了一堆垃圾,因为他们为了什么都得不到而放弃了所有好的东西。

By writing good, readable code first, most of you performance problems will solve themselves. And if later you find your performance is lacking, it's now easy to add a profiler to your nice, clean code, and find out where the problem is.

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

That all said, std::queue is only an adapter. It provides the safe interface, but uses a different container on the inside. You can choose this underlying container, and this allows a good deal of flexibility.

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

So, which underlying container should you use? We know that std::list and std::deque both provide the necessary functions (push_back(), pop_front(), and front()), so how do we decide?

那么,应该使用哪个底层容器呢?我们知道std::list和std::deque都提供了必要的函数(push_back()、pop_front()和front()),那么我们如何决定呢?

First, understand that allocating (and deallocating) memory is not a quick thing to do, generally, because it involves going out to the OS and asking it to do something. A list has to allocate memory every single time something is added, and deallocate it when it goes away.

首先,要明白,一般来说,分配(和释放)内存不是一件容易的事情,因为它涉及到到到操作系统,并要求它做一些事情。一个列表必须在每次添加某个东西时分配内存,并在它离开时释放它。

A deque, on the other hand, allocates in chunks. It will allocate less often than a list. Think of it as a list, but each memory chunk can hold multiple nodes. (Of course, I'd suggest that you really learn how it works.)

另一方面,deque也分配到块中。它会比列表分配得更少。把它看作一个列表,但是每个内存块可以容纳多个节点。(当然,我建议你真正了解它是如何工作的。)

So, with that alone a deque should perform better, because it doesn't deal with memory as often. Mixed with the fact you're handling data of constant size, it probably won't have to allocate after the first pass through the data, whereas a list will be constantly allocating and deallocating.

因此,单就这一点而言,deque应该表现得更好,因为它不经常处理内存。与处理常量大小的数据相混合,在第一次传递数据之后,它可能不需要进行分配,而列表将不断地进行分配和分配。

A second thing to understand is cache performance. Going out to RAM is slow, so when the CPU really needs to, it makes the best out of this time by taking a chunk of memory back with it, into cache. Because a deque allocates in memory chunks, it's likely that accessing an element in this container will cause the CPU to bring back the rest of the container as well. Now any further accesses to the deque will be speedy, because the data is in cache.

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

This is unlike a list, where the data is allocated one at a time. This means that data could be spread out all over the place in memory, and cache performance will be bad.

这与列表不同,在列表中每次分配一个数据。这意味着数据可以在内存中到处分布,缓存性能将会很差。

So, considering that, a deque should be a better choice. This is why it is the default container when using a queue. That all said, this is still only a (very) educated guess: you'll have to profile this code, using a deque in one test and list in the other to really know for certain.

因此,考虑到这一点,deque应该是更好的选择。这就是为什么在使用队列时它是默认的容器。所有这些都说明,这仍然只是一个(非常)有根据的猜测:您必须对这段代码进行概要分析,在一个测试中使用deque,在另一个测试中使用list,才能真正确定。

But remember: get the code working with a clean interface, then worry about performance.

但是请记住:让代码使用干净的接口,然后考虑性能。

John raises the concern that wrapping a list or deque will cause a performance decrease. Once again, he nor I can say for certain without profiling it ourselves, but chances are that the compiler will inline the calls that the queue makes. That is, when you say queue.push(), it will really just say queue.container.push_back(), skipping the function call completely.

John担心包装列表或deque会导致性能下降。同样,他和我都可以肯定地说,而不必自己分析它,但是编译器很可能会内联队列发出的调用。也就是说,当您说queue.push()时,它实际上只会说queue.container.push_back(),完全跳过函数调用。

Once again, this is only an educated guess, but using a queue will not degrade performance, when compared to using the underlying container raw. Like I've said before, use the queue, because it's clean, easy to use, and safe, and if it really becomes a problem profile and test.

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

#2


26  

Check out std::queue. It wraps an underlying container type, and the default container is std::deque.

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

#3


10  

Where performance really matters, check out the Boost circular buffer library.

如果性能真的很重要,请查看Boost循环缓冲区库。

#4


6  

I continually push_back new elements while pop_front ing the oldest element (about a million time).

我不断地使用push_back新元素,而pop_front是最古老的元素(大约一百万次)。

A million is really not a big number in computing. As others have suggested, use a std::queue as your first solution. In the unlikely event of it being too slow, identify the bottleneck using a profiler (do not guess!) and re-implement using a different container with the same interface.

一百万在计算中并不是一个很大的数字。正如其他人所建议的,使用std::queue作为您的第一个解决方案。在不太可能出现的情况下,使用分析器(不要猜测!)识别瓶颈,并使用具有相同接口的不同容器重新实现。

#5


5  

Why not std::queue? All it has is push_back and pop_front.

为什么不std::队列?它只有push_back和pop_front。

#6


3  

A queue is probably a simpler interface than a deque but for such a small list, the difference in performance is probably negligible.

队列可能是比deque更简单的接口,但对于如此小的列表,性能上的差异可能可以忽略不计。

Same goes for list. It's just down to a choice of what API you want.

同样适用于列表。这取决于你想要什么API。