С
- они являются одновременно непрерывными контейнерами памяти;
- функция мудрая, у deque есть почти все, что есть у вектора, но больше, так как более эффективно вставлять спереди.
Почему кто-то предпочитает std::vector
- std::deque
?
С
Почему кто-то предпочитает std::vector
- std::deque
?
Элементы в deque
не смежны в памяти; Элементы vector
гарантированы. Поэтому, если вам нужно взаимодействовать с простой библиотекой C, которая нуждается в непрерывных массивах, или если вы заботитесь (о многом) о пространственной локальности, то вы можете предпочесть vector
. Кроме того, поскольку существует некоторая дополнительная бухгалтерская отчетность, другие операционные системы, вероятно, (немного) дороже, чем их эквивалентные операции vector
. С другой стороны, использование многих/больших экземпляров vector
может привести к ненужной фрагментации кучи (замедлению вызовов до new
).
Кроме того, как указано в другом месте в StackOverflow, здесь более хорошее обсуждение: http://www.gotw.ca/gotw/054.htm.
Чтобы узнать разницу, следует знать, как обычно выполняется deque
. Память выделяется в блоках равных размеров, и они соединены вместе (как массив или, возможно, вектор).
Итак, чтобы найти n-й элемент, вы найдете соответствующий блок, затем получите доступ к элементу внутри него. Это постоянное время, потому что это всегда ровно 2 поиска, но это еще больше, чем вектор.
vector
также хорошо работает с API-интерфейсами, которые хотят иметь непрерывный буфер, потому что они либо являются API-интерфейсами C, либо более универсальны в том, что они могут принимать указатель и длину. (Таким образом, вы можете иметь вектор под или регулярный массив и вызывать API из вашего блока памяти).
Где deque
имеет самые большие преимущества:
Вторая из них менее известна, но для очень больших размеров коллекции:
Когда я имел дело с большими коллекциями в прошлом и перешел от смежной модели к блочной модели, мы смогли хранить примерно в 5 раз большую коллекцию, прежде чем у нас закончилась память в 32-битной системе. Отчасти это связано с тем, что при перераспределении на самом деле необходимо было сохранить старый блок, а также новый, прежде чем он скопировал элементы.
Сказав все это, вы можете столкнуться с проблемами с std::deque
в системах, которые используют "оптимистичное" распределение памяти. Хотя его попытки запросить большой размер буфера для перераспределения a vector
, вероятно, будут отвергнуты в какой-то момент с помощью bad_alloc
, оптимистический характер распределителя, скорее всего, всегда предоставит запрос для меньшего буфера, запрошенный deque
и это может привести к тому, что операционная система убьет процесс, чтобы попытаться получить некоторую память. Какой бы он ни выбрал, может быть не слишком приятным.
Обходные пути в таком случае либо устанавливают флаги системного уровня, чтобы переопределять оптимистическое распределение (не всегда выполнимое), либо управлять памятью несколько более вручную, например. используя собственный распределитель, который проверяет использование памяти или аналогичный. Очевидно, не идеальный. (Что может ответить на ваш вопрос, как предпочесть вектор...)
Я реализовал как вектор, так и deque несколько раз. deque намного сложнее с точки зрения реализации. Это усложнение приводит к большему количеству кода и более сложному коду. Таким образом, вы, как правило, видите, что размер кода попадает, когда вы выбираете deque over vector. Вы также можете столкнуться с небольшим быстродействием, если ваш код использует только те вещи, которые вектор превосходит (т.е. Push_back).
Если вам нужна двойная очередь, deque - явный победитель. Но если вы делаете большую часть своих вставок и стираетесь сзади, вектор станет явным победителем. Когда вы не уверены, объявите свой контейнер с typedef (поэтому его легко переключаться взад-вперед) и измерять.
std::deque
не имеет гарантированной непрерывной памяти - и это часто несколько медленнее для индексированного доступа. Deque обычно реализуется как "список векторов".
Согласно http://www.cplusplus.com/reference/stl/deque/, "в отличие от векторов, у deques не гарантируется наличие всех его элементов в смежных местах хранения, исключая при этом возможность безопасного доступа через арифметику указателя."
Deques немного сложнее, отчасти потому, что они не обязательно имеют смежную макет памяти. Если вам нужна эта функция, вы не должны использовать deque.
(Раньше мой ответ приводил к отсутствию стандартизации (из того же источника, что и выше, "deques могут быть реализованы конкретными библиотеками по-разному" ), но это фактически относится к практически любому типу данных стандартной библиотеки.)
Deque - это контейнер последовательности, который позволяет произвольный доступ к ним, но не гарантирует непрерывного хранения.
Я думаю, что хорошая идея провести тест производительности каждого случая. И принимайте решение, полагаясь на эти тесты.
Я бы предпочел std::deque
чем std::vector
в большинстве случаев.
Вы не хотели бы, чтобы вектор выполнял эти результаты теста (с исходным кодом).
Конечно, вы должны протестировать свое приложение/среду, но в целом:
Еще несколько размышлений и примечание для рассмотрения round_buffer.
С одной стороны, вектор довольно часто просто быстрее, чем deque. Если вы действительно не нужны все функции deque, используйте вектор.
С другой стороны, иногда вам делать нужны функции, которые вектор вам не дает, и в этом случае вы должны использовать deque. Например, я призываю всех попытаться переписать этот код, не используя deque и без особого изменения алгоритма.