Есть хорошо известное изображение (шпаргалка) под названием «Выбор контейнера C ++». Это блок-схема, чтобы выбрать лучший контейнер для желаемого использования.
Кто-нибудь знает, есть ли уже версия на C ++ 11?
Это предыдущий:

Есть хорошо известное изображение (шпаргалка) под названием «Выбор контейнера C ++». Это блок-схема, чтобы выбрать лучший контейнер для желаемого использования.
Кто-нибудь знает, есть ли уже версия на 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) отделен от значения, с которым он связан, таким образом,map
1.3. Идентификатор уникален, поэтому дубликат не должен закрадываться.
Окончательный ответ: std::unordered_map<ID, PersonData>.
Вопрос 2: память стабильна ?
listВопрос 2.1: который ?
list; a forward_listполезен только для уменьшения занимаемой памяти.Вопрос 3: Динамический размер ?
{ ... }синтаксис), тогда используйте array, Он заменяет традиционный C-массив, но с удобными функциями.Вопрос 4: двусторонний ?
deque, в противном случае используйте a vector.Вы заметите, что по умолчанию, если вам не нужен ассоциативный контейнер, ваш выбор будет a 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) против O (log n), это не влияет на семантику; Я удалю «эффективно» из примера и заменю на «легко».
dequeбыло ли это свойство тоже?
dequeэлементы стабильны, только если вы нажмете / поп с любого конца; если вы начнете вставлять / стирать в середине, то до N / 2 элементов будут перетасовываться, чтобы заполнить созданный промежуток.
Мне нравится ответ Матье, но я собираюсь пересказать блок-схему как это:
По умолчанию, если вам нужен контейнер с вещами, используйте std::vector. Таким образом, любой другой контейнер оправдывается только предоставлением некоторой функциональной альтернативы std::vector.
std::vectorтребует, чтобы его содержимое было пригодно для перемещения, поскольку оно должно иметь возможность перетасовывать предметы вокруг. Это не страшное бремя для содержимого (обратите внимание, что конструкторы по умолчанию не требуются , emplaceи так далее). Однако большинство других контейнеров не требуют какого-либо конкретного конструктора (опять же, спасибо emplace). Поэтому, если у вас есть объект, в котором вы абсолютно не можете реализовать конструктор перемещения, вам придется выбрать что-то другое.
A std::dequeбудет общей заменой, имеющей многие свойства std::vector, но вы можете вставить ее только на обоих концах deque. Вставки посередине требуют перемещения. А std::listне предъявляет никаких требований к его содержанию.
std::vector<bool>не является. Ну, это стандартно. Но это не vectorв обычном смысле, поскольку операции, которые std::vectorобычно разрешены, запрещены. И это, безусловно , не содержит boolс .
Поэтому, если вам нужно реальное vectorповедение из контейнера bools, вы не получите его std::vector<bool>. Так что вам придется сделать должным с std::deque<bool>.
Если вам нужно найти элементы в контейнере, а поисковый тег не может быть просто индексом, то вам, возможно, придется отказаться std::vectorв пользу setи map. Обратите внимание на ключевое слово « может »; Сортировка std::vectorиногда является разумной альтернативой. Или Boost.Container 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производительность вставки может быть не такой плохой, как раньше. В некоторых реализациях реализована форма копирования элементов на основе семантики перемещения (так называемая «swaptimization»), но теперь, когда перемещение является частью языка, оно предписано стандартом.
std::arrayэто хороший контейнер, если вы хотите наименьшее количество динамических выделений. Это просто обёртка вокруг C-массива; это означает, что его размер должен быть известен во время компиляции . Если вы можете жить с этим, то используйте 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 версии, в первую очередь в связи с тем , что я действительно не люблю связанные узлы. Связанные узлы-контейнеры обычно могут работать быстрее, чем несвязанные контейнеры, за исключением нескольких редких ситуаций. Если вы не знаете, что это за ситуации, и не имеете доступа к boost, не используйте контейнеры связанных узлов. (std :: list, std :: slist, std :: map, std :: multimap, std :: set, std :: multiset). Этот список фокусируется в основном на небольших и средних контейнерах, потому что (A) это 99,99% от того, с чем мы имеем дело в коде, и (B) Большому количеству элементов нужны собственные алгоритмы, а не разные контейнеры.