Чтобы понять разницу, нужно знать, как deque
это вообще реализовано. Память распределяется блоками равного размера, и они связаны вместе (как массив или, возможно, вектор).
Итак, чтобы найти n-й элемент, вы находите соответствующий блок, а затем получаете доступ к элементу внутри него. Это постоянное время, потому что это всегда ровно 2 поиска, но это все равно больше, чем вектор.
vector
также хорошо работает с API-интерфейсами, которым нужен непрерывный буфер, потому что они либо являются API-интерфейсами C, либо более универсальны с точки зрения возможности принимать указатель и длину. (Таким образом, у вас может быть вектор под ним или обычный массив и вызов API из вашего блока памяти).
Где deque
его самые большие преимущества:
- При увеличении или уменьшении коллекции с любого конца
- Когда вы имеете дело с очень большими коллекциями.
- Когда вы имеете дело с bools и вам действительно нужны bools, а не bitset.
Второй из них менее известен, но для очень больших размеров коллекции:
- Стоимость перераспределения велика
- Накладные расходы, связанные с поиском непрерывного блока памяти, являются ограничительными, поэтому вы можете быстрее исчерпать память.
Когда в прошлом я имел дело с большими коллекциями и перешел от непрерывной модели к блочной модели, мы смогли хранить примерно в 5 раз больше коллекции, прежде чем у нас закончилась память в 32-битной системе. Отчасти это связано с тем, что при перераспределении фактически необходимо было сохранить старый блок, а также новый, прежде чем копировать элементы.
Сказав все это, вы можете столкнуться с проблемами std::deque
в системах, которые используют «оптимистичное» распределение памяти. Хотя его попытки запросить большой размер буфера для перераспределения a vector
, вероятно, будут отклонены в какой-то момент с помощью a bad_alloc
, оптимистичный характер распределителя, вероятно, всегда будет предоставлять запрос на меньший буфер, запрошенный a, deque
и это может вызвать операционная система, чтобы убить процесс, чтобы попытаться получить некоторую память. То, что он выберет, может оказаться не слишком приятным.
Обходными путями в таком случае являются либо установка флагов системного уровня для переопределения оптимистичного распределения (не всегда выполнимо), либо несколько более ручное управление памятью, например, использование вашего собственного распределителя, который проверяет использование памяти, или подобное. Очевидно, не идеально. (Что может ответить на ваш вопрос о предпочтении вектора ...)
std::deque
имеет очень маленький максимальный размер блока (~ 16 байт, если я правильно помню; возможно, 32), и поэтому не очень хорошо работает для реалистичных приложений. Adeque<T>
wheresizeof(T) > 8
(или 16? Это небольшое число) имеет примерно те же характеристики производительности, что и avector<T*>
, где каждый элемент выделяется динамически. Другие реализации имеют разные максимальные размеры блоков, поэтому писать код с относительно одинаковыми характеристиками производительности на разных платформах сложноdeque
.