Є добре відоме зображення (шпаргалка) під назвою "C ++ Container choice". Це схема вибору найкращого контейнера для потрібного використання.
Хтось знає, чи є вже версія C ++ 11?
Це попередній:

Є добре відоме зображення (шпаргалка) під назвою "C ++ Container choice". Це схема вибору найкращого контейнера для потрібного використання.
Хтось знає, чи є вже версія C ++ 11?
Це попередній:

Відповіді:
Не те, про що я знаю, але, мабуть, це можна зробити текстуально. Крім того, діаграма трохи відключена, бо listзагалом не такий хороший контейнер, і це не так forward_list. Обидва списки є дуже спеціалізованими контейнерами для нішевих додатків.
Щоб скласти таку діаграму, вам просто потрібно два простих рекомендації:
Турбуватися про продуктивність спочатку марно. Найважливіші міркування "О" дійсно виникають лише тоді, коли ви починаєте обробляти кілька тисяч (або більше) предметів.
Є дві великі категорії контейнерів:
findопераціюа потім ви можете створити кілька адаптерів на них: stack, queue, priority_queue. Я залишу адаптери тут, вони достатньо спеціалізовані, щоб бути впізнаваними.
Питання 1: Асоціативний ?
Питання 1.1: Упорядковано ?
unordered_контейнер, інакше використовуйте його традиційний замовлений аналог.Питання 1.2: Окремий ключ ?
map, інакше використовуйте asetПитання 1.3: Дублікати ?
multi, інакше не робіть.Приклад:
Припустимо, що у мене є декілька осіб з унікальним ідентифікатором, пов’язаним з ними, і я хотів би максимально просто отримати дані про особу з її ідентифікатора.
Я хочу findфункцію, таким чином, асоціативний контейнер
1.1. Я не міг менше дбати про замовлення, таким чином unordered_контейнер
1.2. Мій ключ (ID) окремо від значення, з яким він асоціюється, таким чином amap
1.3. Ідентифікатор унікальний, тому жоден дублікат не повинен повзати.
Відповідь: std::unordered_map<ID, PersonData>.
Питання 2: Стабільна пам'ять ?
listПитання 2.1: Що ?
list; a forward_listкорисний лише для меншої площі пам'яті.Питання 3: Динамічно розмір ?
{ ... }синтаксис), тоді використовуйте array. Він замінює традиційний C-масив, але зручними функціями.Питання 4: Подвійний ?
deque, інакше використовуйте vector.Ви помітите , що, за замовчуванням, якщо не потрібен асоціативний контейнер, ваш вибір буде vector. Виявляється, це також рекомендація Саттера і Строструпа .
arrayне вимагає конструктивного типу за замовчуванням; 2) вибір multis - це не стільки про те, щоб дублікати було дозволено, а більше про те, чи зберігає їх значення (ви можете помістити дублікати в неконтейнери multi, просто трапляється, що зберігається лише один).
map.find(key)набагато приємніше, ніж std::find(map.begin(), map.end(), [&](decltype(map.front()) p) { return p.first < key; }));хоча, тому важливо, семантично, findце функція члена, а не функція <algorithm>. Що стосується O (1) vs O (log n), то це не впливає на семантику; Я приберу "ефективно" з прикладу і заміню його на "легко".
dequeмає і ця властивість?
dequeелементі елементи стабільні лише у тому випадку, якщо ви натискаєте / стискаєте на будь-якому кінці; якщо ви почнете вставляти / стирати в середині, то до N / 2 елементів змішуються, щоб заповнити створений пробіл.
Мені подобається відповідь Матьє, але я збираюсь переробити блок-схему так:
За замовчуванням, якщо вам потрібен контейнер з речами, використовуйте std::vector. Таким чином, кожен інший контейнер виправданий лише наданням певної функціональної альтернативи std::vector.
std::vectorвимагає, щоб його вміст було зручним для переміщення, оскільки йому потрібно вміти переміщувати елементи навколо. Це не є страшним тягарем для вмісту (зауважте, що конструктори за замовчуванням не потрібні , завдяки emplaceтощо). Однак для більшості інших контейнерів не потрібен конкретний конструктор (знову ж таки, завдяки emplace). Тож якщо у вас є об'єкт, де ви абсолютно не можете реалізувати конструктор переміщення, вам доведеться вибрати щось інше.
A std::dequeбула б загальною заміною, яка має багато властивостей std::vector, але вставляти їх можна лише на обох кінцях деки. Вставки в середині вимагають переміщення. Місце std::listне пред'являє жодних вимог до його змісту.
std::vector<bool>не. Ну, це стандартно. Але це не vectorу звичному розумінні, оскільки операції, які std::vectorзазвичай дозволяють, заборонені. І це, безумовно , не містить bools .
Тому, якщо вам потрібна реальна vectorповедінка з контейнера bools, ви не збираєтесь її отримувати std::vector<bool>. Тож вам доведеться погодитись із std::deque<bool>.
Якщо вам потрібно знайти елементи в контейнері, а пошуковий тег не може бути просто індексом, можливо, вам доведеться відмовитися std::vectorна користь setі map. Зверніть увагу на ключове слово " може "; сортування std::vector- іноді розумна альтернатива. Або Boost.Container's flat_set/map, який реалізує відсортовану std::vector.
Зараз існує чотири варіанти, кожна з яких має власні потреби.
mapколи тег пошуку - це не те саме, що предмет, який ви шукаєте. В іншому випадку використовуйте set.unorderedколи у контейнері багато предметів, а ефективність пошуку абсолютно не повинна бути O(1), а не O(logn).multiякщо вам потрібно кілька елементів, щоб мати один і той же тег пошуку.Якщо вам потрібен контейнер з предметами, який слід завжди сортувати на основі певної операції порівняння, ви можете використовувати set. Або multi_setякщо вам потрібно кілька предметів, щоб мати однакове значення.
Або ви можете використовувати відсортовану std::vector, але вам доведеться тримати її відсортованою.
Коли ітератори та посилання недійсні, іноді викликає занепокоєння. Якщо вам потрібен список елементів, наприклад, у вас є ітератори / покажчики на ці предмети в різних інших місцях, то std::vectorпідхід до визнання недійсним може виявитися недоцільним. Будь-яка операція вставки може спричинити недійсність, залежно від поточного розміру та потужності.
std::listнадає тверду гарантію: ітератор та пов'язані з ним посилання / покажчики недійсні лише тоді, коли сам товар вилучено з контейнера. std::forward_listчи є, якщо пам'ять викликає серйозне занепокоєння.
Якщо це занадто сильна гарантія, std::dequeнадає більш слабку, але корисну гарантію. Недійсність є результатом вставок посередині, але вставки в голову або хвіст викликають лише недійсні ітератори , а не покажчики / посилання на елементи в контейнері.
std::vector забезпечує лише дешеву вставку в кінці (і навіть тоді вона стає дорогою, якщо ви підірвете ємність).
std::listє дорогим з точки зору продуктивності (кожен щойно вставлений елемент коштує розподілу пам'яті), але він є послідовним . Він також пропонує періодично незамінну можливість перемішувати предмети практично без витрат на продуктивність, а також торгувати предметами з іншими std::listконтейнерами того ж типу без втрати продуктивності. Якщо вам потрібно перетасувати речі навколо багато , використання std::list.
std::dequeзабезпечує введення / видалення постійного часу на голові та хвості, але вставка посередині може бути досить дорогою. Тож якщо вам потрібно додати / вилучити речі спереду та ззаду, std::dequeможливо, це вам потрібно.
Слід зазначити, що завдяки семантиці переміщення std::vectorпродуктивність вставки може бути не такою поганою, як раніше. Деякі реалізації реалізували форму копіювання елементів на основі семантичного переміщення (так звана "своптимізація"), але тепер, коли переміщення є частиною мови, це відповідає мандату.
std::array- прекрасний контейнер, якщо ви хочете отримати найменші динамічні виділення. Це просто обгортка навколо масиву С; це означає, що його розмір повинен бути відомий під час компіляції . Якщо ви можете з цим жити, то використовуйте std::array.
Як сказано, використання std::vectorта reserveрозмір розміру буде працювати так само добре для обмежених std::vector. Таким чином, фактичний розмір може змінюватись, і ви отримуєте лише одне розподілення пам'яті (якщо тільки ви не збільшите ємність).
std::sort, є також std::inplace_mergeцікавий, щоб легко розмістити нові елементи (а не std::lower_bound+ std::vector::insertдзвінок). Приємно дізнатися про flat_setі flat_map!
vector<bool>є vector<char>.
std::allocator<T>це не підтримує це вирівнювання (і я не знаю, чому б цього не було), ви завжди можете використовувати власний спеціальний розподільник.
std::vector::resizeмає перевантаження, яке не приймає значення (воно просто приймає новий розмір; будь-які нові елементи будуть створені за замовчуванням на місці). Крім того, чому компілятори не можуть правильно вирівняти параметри значення, навіть коли їм оголошено таке вирівнювання?
bitsetдля bool, якщо ви знаєте розмір заздалегідь en.cppreference.com/w/cpp/utility/bitset
Ось версія C ++ 11 вищевказаної блок-схеми. [спочатку розміщено без атрибуції своєму первісному автору Мікаелю Персону ]

Ось швидке віджимання, хоча воно, певно, потребує роботи
Should the container let you manage the order of the elements?
Yes:
Will the container contain always exactly the same number of elements?
Yes:
Does the container need a fast move operator?
Yes: std::vector
No: std::array
No:
Do you absolutely need stable iterators? (be certain!)
Yes: boost::stable_vector (as a last case fallback, std::list)
No:
Do inserts happen only at the ends?
Yes: std::deque
No: std::vector
No:
Are keys associated with Values?
Yes:
Do the keys need to be sorted?
Yes:
Are there more than one value per key?
Yes: boost::flat_map (as a last case fallback, std::map)
No: boost::flat_multimap (as a last case fallback, std::map)
No:
Are there more than one value per key?
Yes: std::unordered_multimap
No: std::unordered_map
No:
Are elements read then removed in a certain order?
Yes:
Order is:
Ordered by element: std::priority_queue
First in First out: std::queue
First in Last out: std::stack
Other: Custom based on std::vector?????
No:
Should the elements be sorted by value?
Yes: boost::flat_set
No: std::vector
Ви можете помітити, що це дико відрізняється від версії C ++ 03, насамперед через те, що я дійсно не люблю пов'язані вузли. З'єднані контейнери з вузлами зазвичай можуть бути обіграні по продуктивності не пов'язаним контейнером, за винятком кількох рідкісних ситуацій. Якщо ви не знаєте, що це за ситуації, і у вас є доступ до підвищення, не використовуйте пов'язані контейнери для вузлів. (std :: список, std :: slist, std :: map, std :: multimap, std :: set, std :: multiset). Цей список зосереджується здебільшого на малих та середньосторонніх контейнерах, оскільки (А) це 99,99% від того, що ми маємо справу з кодом, і (В) Великій кількості елементів потрібні спеціальні алгоритми, а не різні контейнери.