Оскільки відповідей існує безліч, ви можете заплутатися, але підсумовуючи:
Використовуйте a std::queue
. Причина цього проста: це структура FIFO. Ви хочете FIFO, ви використовуєте std::queue
.
Це дає зрозуміти ваші наміри будь-кому іншому, і навіть вам самим. А std::list
чи std::deque
ні. Список можна вставляти та видаляти де завгодно, чого не слід робити структурі FIFO, а deque
можна додавати та видаляти з будь-якого кінця, що також не може робити структура FIFO.
Ось чому вам слід використовувати a queue
.
Тепер ви запитали про продуктивність. По-перше, завжди пам’ятайте про це важливе правило: спочатку хороший код, остання продуктивність.
Причина цього проста: люди, які прагнуть до продуктивності до чистоти та елегантності, майже завжди закінчують останніми. Їх код стає нечистотою, тому що вони відмовились від усього доброго, щоб насправді нічого з цього не отримати.
Написавши спочатку хороший, читабельний код, більшість з вас проблеми з продуктивністю вирішать самі. І якщо пізніше ви виявите, що вашої продуктивності не вистачає, тепер легко додати профайлер до вашого приємного, чистого коду і з’ясувати, де проблема.
Все сказане - std::queue
це лише адаптер. Він забезпечує безпечний інтерфейс, але використовує інший контейнер всередині. Ви можете вибрати цей основний контейнер, і це забезпечує значну гнучкість.
Отже, який базовий контейнер слід використовувати? Ми знаємо , що std::list
і std::deque
як забезпечити необхідні функції ( push_back()
, pop_front()
і front()
), так як ми вирішили?
По-перше, зрозумійте, що виділення (і вивільнення) пам’яті, як правило, не є швидким завданням, оскільки воно передбачає вихід до ОС та прохання її щось зробити. A list
повинен виділяти пам'ять кожного разу, коли щось додається, і звільняти її, коли вона зникає.
А deque
, з іншого боку, розподіляє шматками. Він буде виділяти рідше, ніж a list
. Подумайте про це як про список, але кожен фрагмент пам’яті може містити кілька вузлів. (Звичайно, я б запропонував вам справді дізнатися, як це працює .)
Отже, лише з цим a deque
повинен працювати ефективніше, оскільки він не так часто справляється з пам’яттю. У поєднанні з тим, що ви обробляєте дані постійного розміру, їм, ймовірно, не доведеться розподіляти їх після першого проходження через дані, тоді як список буде постійно розподіляти та звільняти.
Друге, що слід зрозуміти - це продуктивність кешу . Вихід до оперативної пам’яті відбувається повільно, тому, коли процесору справді потрібно, він робить все можливе, забираючи частину пам’яті назад у кеш. Оскільки deque
розподіл у фрагментах пам'яті, цілком ймовірно, що доступ до елемента в цьому контейнері призведе до того, що процесор поверне назад і решту контейнера. Тепер будь-який подальший доступ до deque
буде швидким, оскільки дані знаходяться в кеші.
Це на відміну від списку, де дані розподіляються по одному. Це означає, що дані можуть поширюватися повсюдно в пам'яті, і продуктивність кешу буде поганою.
Отже, зважаючи на це, deque
кращим вибором має бути a. Ось чому це контейнер за замовчуванням при використанні queue
. З усього сказаного, це все ще лише (дуже) освічена здогадка: вам доведеться профілювати цей код, використовуючи deque
в одному тесті, а list
в іншому, щоб насправді точно знати.
Але пам’ятайте: змушуйте код працювати з чистим інтерфейсом, тоді турбуйтеся про продуктивність.
Джон висловлює занепокоєння тим, що обгортання list
або deque
спричинить зниження продуктивності. Ще раз, ні він, ні я не можемо сказати напевно, не профілюючи це самі, але, швидше за все, компілятор вбудує дзвінки, які queue
робить. Тобто, коли ви говорите queue.push()
, це справді просто скаже queue.container.push_back()
, повністю пропускаючи виклик функції.
Ще раз, це лише освічена здогадка, але використання queue
волі не погіршить продуктивність у порівнянні з використанням базового контейнера raw. Як я вже говорив раніше, використовуйте queue
, оскільки він чистий, простий у використанні та безпечний, і якщо він справді стає проблемним профілем та тестом.