Оскільки
- вони обидва є суміжними контейнерами пам'яті;
- особливо мудро, деке має майже все, що має вектор, але більше, оскільки його ефективніше вставляти спереду.
Чому хтось вважає 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
в системах, які використовують "оптимістичний" розподіл пам'яті. Хоча спроби запитати великий розмір буфера для перерозподілу vector
заповіту в певний момент отримають відмову з a bad_alloc
, оптимістичний характер розподільника, швидше за все, завжди задовольняє запит на менший буфер, запитуваний a, deque
що, ймовірно, може спричинити операційна система, щоб убити процес, щоб спробувати отримати трохи пам'яті. Який би з них він не вибрав, може бути не надто приємним.
Вирішення проблем у такому випадку - це встановлення прапорів системного рівня, щоб замінити оптимістичне розподіл (не завжди можливо), або управління пам’яттю дещо ручніше, наприклад, за допомогою власного розподільника, який перевіряє використання пам’яті тощо. Очевидно, не ідеально. (Що може відповісти на ваше запитання щодо переваги вектору ...)
Я реалізовував як вектор, так і deque кілька разів. deque набагато складніший з точки зору реалізації. Це ускладнення перетворюється на більше коду та більш складний код. Отже, ви зазвичай бачите розмір коду, коли ви вибираєте deque замість вектора. Ви також можете відчути невелику швидкість удару, якщо ваш код використовує лише те, у чому перевершує вектор (тобто push_back).
Якщо вам потрібна черга з подвійним кінцем, deque є безперечним переможцем. Але якщо ви робите більшість своїх вставок і стирань ззаду, вектор буде безперечним переможцем. Коли ви не впевнені, оголосіть свій контейнер typedef (щоб його було легко перемикати вперед-назад) і виміряйте.
vector
.) У своїй відповіді я написав імплементацію, на яку посилається нижче . Це може бути настільки ж швидким, як vector
набагато ширше застосовним (наприклад, під час швидкої черги).
std::deque
не має гарантованої безперервної пам’яті - і це часто дещо повільніше для індексованого доступу. Деке зазвичай реалізується як "список вектора".
Відповідно до http://www.cplusplus.com/reference/stl/deque/ , "на відміну від векторів, декам не гарантовано мати всі його елементи в сусідніх місцях зберігання, усуваючи таким чином можливість безпечного доступу через арифметику покажчиків".
Декети дещо складніші, частково тому, що вони не обов'язково мають суміжний макет пам'яті. Якщо вам потрібна ця функція, не слід використовувати деке.
(Раніше моя відповідь спричинила відсутність стандартизації (з того самого джерела, що і вище, "деко можуть бути реалізовані конкретними бібліотеками по-різному"), але це насправді стосується майже будь-якого стандартного типу даних бібліотеки.)
std::deque
не менш стандартизований, ніж std::vector
. Я не вірю, що вимоги до складності std::deque
можна виконати при суміжному зберіганні.
deque
не можуть відповідати суміжним сховищам?
deque
, а саме, що вставка на кінцях не може призвести до недійсності посилань на існуючі елементи. Ця вимога передбачає розрив пам'яті.
Я думаю, що це гарна ідея зробити тест на ефективність кожного випадку. І приймати рішення, покладаючись на ці тести.
Я віддав би перевагу, std::deque
ніж std::vector
у більшості випадків.
vector
. Ми можемо зробити висновок, що чому б ні - це наслідок. Сказати, що ви віддаєте перевагу deque
з невідомих причин невстановленим тестам, не є відповіддю.
Ви не віддаєте перевагу вектору, аніж декому відповідно до цих результатів тесту (із джерелом).
Звичайно, ви повинні протестувати у своєму додатку / середовищі, але коротко:
Ще трохи роздумів та примітка, яку слід розглянути circular_buffer.
З одного боку, вектор досить часто просто швидший, ніж deque. Якщо вам насправді не потрібні всі функції deque, використовуйте вектор.
З іншого боку, іноді ви робите функції потрібно , який вектор не дає вам, в цьому випадку ви повинні використовувати Deque. Наприклад, я кидаю виклик кожному, хто намагається переписати цей код , не використовуючи деке і не змінюючи алгоритму.
push_back
і тій же серії pop_back
операцій deque<int>
завжди принаймні на 20% швидше, ніж vector<int>
у моїх тестах (gcc з O3). Я думаю, саме тому deque
це стандартний вибір для таких речей, як std::stack
...
Зверніть увагу, що векторна пам’ять перерозподіляється в міру зростання масиву. Якщо у вас є вказівники на векторні елементи, вони стануть недійсними.
Крім того, якщо стерти елемент, ітератори стають недійсними (але не "для (авто ...)").
Редагувати: змінено "deque" на "vector"
std::deque
має дуже малий максимальний розмір блоку (~ 16 байт, якщо я правильно пам'ятаю; можливо, 32), і як така не працює дуже ефективно для реалістичних додатків.deque<T>
, Деsizeof(T) > 8
(або 16? Це невелике число) має приблизно ту ж характеристику продуктивності в якостіvector<T*>
, де кожен елемент виділяється динамічно. Інші реалізації мають різні максимальні розміри блоків, тому писати код, який має відносно однакові характеристики продуктивності на різних платформах, важкоdeque
.