Какой контейнер STL следует использовать для FIFO?

какой контейнер STL лучше всего подойдет моим потребностям? У меня в основном есть 10 элементов широкий контейнер, в котором я постоянно push_back новые элементы, в то время как pop_front ing самый старый элемент (около миллиона раз).

в настоящее время я использую std::deque для задачи, но было интересно, если std::list было бы более эффективно, так как мне не нужно было бы перераспределять себя (или, может быть, я ошибаюсь std::deque на std::vector?). Или есть еще более эффективный контейнер для моего нужно?

P. S. Мне не нужен случайный доступ к

6 ответов


поскольку существует множество ответов, вы можете быть смущены, но подытожить:

использовать std::queue. Причина этого проста: это структура FIFO. Вы хотите FIFO, вы используете std::queue.

это делает ваше намерение ясным для кого-либо еще, и даже для себя. А std::list или std::deque нет. Список может вставлять и удалять в любом месте, что не является тем, что должна делать структура FIFO, и deque добавить и удалите с обоих концов, что также не может сделать структура FIFO.

вот почему вы должны использовать queue.

Итак, вы спросили о производительности. Во-первых, всегда помните это важное правило: хороший код, во-первых, производительность последнего.

причина этого проста: люди которые стремятся для представления перед чистотой и элегантностью почти всегда заканчивают последнее. Их код превращается в кашу, потому что они отказался от всего хорошего, чтобы действительно ничего из этого не получить.

написав хороший, читаемый код, большинство из вас проблемы с производительностью решат сами. И если позже вы обнаружите, что ваша производительность отсутствует, теперь легко добавить профилировщик в ваш хороший, чистый код и узнать, где проблема.

вот и все сказано,std::queue Это только адаптер. Она обеспечивает безопасный интерфейс, но использует другой контейнер внутри. Вы можете выбрать эту основу контейнер, и это позволяет много гибкости.

Итак, какой базовый контейнер вы должны использовать? Мы знаем, что std::list и std::deque обеспечивают необходимые функции (push_back(), pop_front() и front()), так как мы решим?

во-первых, поймите, что выделение (и освобождение) памяти-это не быстрая вещь, потому что она включает в себя выход в ОС и просить ее что-то сделать. А list нужно выделять память каждый раз что-то добавляется и освобождается, когда оно уходит.

A deque, С другой стороны, выделяет в куски. Он будет выделять реже, чем list. Думайте об этом как о списке, но каждый кусок памяти может содержать несколько узлов. (Конечно, я бы посоветовал вам действительно узнать, как это работает.)

Итак, с этим однимdeque должен работать лучше, потому что он не имеет дело с памятью так часто. Смешанный с фактом, что вы обрабатываете данные константы размер, вероятно, не придется выделять после первого прохода через данные, в то время как список будет постоянно выделять и освобождать.

второе, что нужно понять производительность кэша. Выход в ОЗУ медленный, поэтому, когда CPU действительно нужно, он делает лучшее из этого времени, взяв с собой кусок памяти обратно в кэш. Потому что deque выделяет в блоках памяти, вероятно, что доступ к элементу в этом контейнере вызовет CPU, чтобы вернуть остальную часть контейнера. Теперь любой дальнейший доступ к deque будет быстрым, потому что данные находятся в кэше.

это не похоже на список, где данные выделяются по одному за раз. Это означает, что данные могут быть распределены по всему месту в памяти, а производительность кэша будет плохой.

Итак, учитывая это, a deque должно быть лучшим выбором. Вот почему это контейнер по умолчанию при использовании queue. Что все сказанное, это все еще только (очень) образованная догадка: вам придется профилировать этот код, используя deque в одном тесте и list в другом, чтобы действительно знать наверняка.

но помните: получите код, работающий с чистым интерфейсом, а затем беспокоиться о производительности.

Джон поднимает озабоченность тем, что обертывание list или deque приведет к снижению производительности. Еще раз, ни он, ни я не можем сказать наверняка, не профилируя его сами, но есть вероятность, что компилятор будет встроен звонки, которые queue делает. То есть, когда вы говорите queue.push(), это очень просто сказать queue.container.push_back(), пропуская вызов функции полностью.

еще раз повторюсь, это только догадка, но с помощью queue не ухудшит производительность по сравнению с использованием базового контейнера raw. Как я уже говорил, используйте queue, потому что он чистый, простой в использовании и безопасный, и если он действительно становится проблемным профилем и тестом.


проверить std::queue. Он обертывает базовый тип контейнера, а контейнер по умолчанию -std::deque.


когда производительность действительно имеет значение, проверьте увеличить круговую буферную библиотеку.


Я постоянно push_back новые элементы в то время как pop_front ing самый старый элемент (примерно миллион раз).

миллион на самом деле не большое число в вычислениях. Как предлагали другие, используйте std::queue Как ваше первое решение. В маловероятном случае, если он будет слишком медленным, определите узкое место с помощью профилировщика (не угадайте!) и повторно реализовать с помощью другого контейнера с тем же интерфейсом.


почему std::queue? Все это push_back и pop_front.


A очереди, вероятно, более простой интерфейс, чем очереди но для такого небольшого списка разница в производительности, вероятно, незначительна.

же список. Это просто выбор того, какой API вы хотите.