Почему я предпочитаю использовать vector для deque
С
- они оба являются смежными контейнерами памяти;
- feature wise, deque имеет почти все, что вектор имеет, но больше, так как он более эффективен для вставки спереди.
почему кто-нибудь предпочитает std::vector
до std::deque
?
9 ответов
элементов deque
are не непрерывен в памяти; vector
элементы гарантированно будут. Поэтому, если вам нужно взаимодействовать с простой библиотекой C, которая нуждается в смежных массивах, или если вы заботитесь (много) о пространственной локальности, то вы можете предпочесть vector
. Кроме того, поскольку существует некоторая дополнительная бухгалтерия, другие ops, вероятно (немного) дороже, чем их эквивалент vector
операции. С другой стороны, используя много / больших экземпляров vector
может привести к ненужная фрагментация кучи (замедление вызовов new
).
также, как указано в другом месте на StackOverflow, здесь больше хорошего обсуждения:http://www.gotw.ca/gotw/054.htm .
чтобы узнать разницу, нужно знать, как deque
обычно реализуется. Память выделяется в блоках равных размеров, и они скованы вместе (как массив или, возможно, вектор).
таким образом, чтобы найти n-й элемент, вы найдете соответствующий блок, а затем получите доступ к элементу внутри него. Это постоянное время, потому что это всегда ровно 2 поиска, но это все еще больше, чем вектор.
vector
также хорошо работает с API, которые хотят непрерывный буфер потому что они либо C API, либо более универсальны в том, что могут принимать указатель и длину. (Таким образом, вы можете иметь вектор под или регулярный массив и вызывать API из блока памяти).
здесь deque
имеет свои большие преимущества:
- при росте или сокращении коллекции с обоих концов
- когда вы имеете дело с очень большими размерами коллекции.
- при работе с bools, и вы действительно хотите bools, а чем bitset.
второй из них менее известен, но для очень больших размеров коллекции:
- стоимость перераспределения велика
- накладные расходы, связанные с поиском смежного блока памяти, ограничительны, поэтому вы можете быстрее запускать память.
когда я имел дело с большими коллекциями в прошлом и перешел от смежной модели к блочной модели, мы смогли сохранить примерно в 5 раз больше коллекции до того, как у нас закончилась память в 32-битной системе. Отчасти это связано с тем, что при повторном выделении ему действительно нужно было сохранить старый блок, а также Новый, прежде чем он скопировал элементы.
сказав Все это, вы можете попасть в беду с std::deque
в системах, использующих "оптимистичное" распределение памяти. В то время как его попытки запросить большой размер буфера для перераспределения vector
вероятно получить отказ в какой-то момент с bad_alloc
, оптимизм распределитель, вероятно, всегда будет предоставлять запрос для меньшего буфера, запрошенного deque
и это, вероятно, заставит операционную систему убить процесс, чтобы попытаться получить некоторую память. Какой бы он ни выбрал, он может оказаться не слишком приятным.
обходными путями в таком случае являются либо установка флагов системного уровня для переопределения оптимистического распределения (не всегда возможно), либо управление памятью несколько более вручную, например, с помощью собственного распределителя, который проверяет использование памяти или подобный. Очевидно, не идеально. (Что может ответить на ваш вопрос о предпочтении vector...)
я реализовал как вектор, так и deque несколько раз. deque значительно сложнее с точки зрения реализации. Это усложнение переводится в более сложный код. Таким образом, вы обычно увидите хит размера кода при выборе deque над вектором. Вы также можете испытать небольшую скорость, если ваш код использует только то, что вектор превосходит (т. е. push_back).
Если вам нужна двойная очередь, deque является явным победителем. Но если вы делаете большинство из ваших вставок и стираний на задней панели вектор будет явным победителем. Когда вы не уверены, объявите свой контейнер с typedef (так что легко переключаться туда и обратно) и измерьте.
std::deque
не имеет гарантированной памяти - и часто несколько медленнее, для индексированного доступа. Deque обычно реализуется как "список векторов".
согласно http://www.cplusplus.com/reference/stl/deque/, " в отличие от векторов, deques не гарантируется наличие всех его элементов в смежных местах хранения, что исключает возможность безопасного доступа через арифметику указателей."
двусторонней очередью немного сложнее, отчасти потому, что они не обязательно связанное с памятью. Если вам нужна эта функция, вы не должны использовать дека.
(ранее мой ответ вызвал отсутствие стандартизации (из того же источника, что и выше, "deques могут быть реализованы конкретными библиотеками по-разному"), но это фактически относится практически к любому стандартному типу данных библиотеки.)
deque-это контейнер последовательности, который позволяет случайный доступ к его элементам, но не гарантируется непрерывное хранение.
Я думаю, что хорошая идея сделать тест производительности каждого случая. И принять решение, опираясь на эти тесты.
Я бы предпочел std::deque
чем std::vector
в большинстве случаев.
вы не желавших предпочитаю вектор к deque согласно эти результаты теста (с источником).
конечно, вы должны протестировать в своем приложении / среде, но вкратце:
- push_back в основном одинакова для всех
- insert, erase в deque намного быстрее, чем list и незначительно быстрее, чем vector
еще несколько размышлений и примечание для рассмотрения circular_buffer.
с одной стороны, вектор довольно часто просто быстрее, чем дека. Если вы на самом деле нужно все функции deque, используйте вектор.
с другой стороны, иногда вы do нужны функции, которые вектор не дает вам, и в этом случае вы должны использовать deque. Например, я призываю любого попытаться переписать код, без использования deque и без существенного изменения алгоритма.