В каком сценарии я использую конкретный контейнер STL?

Я читал на контейнерах STL в своей книге на С++, в частности, в разделе STL и его контейнерах. Теперь я понимаю, что каждый из них имеет свои собственные специфические свойства, и я близок к запоминанию всех из них... Но то, что я еще не понимаю, в том, какой сценарий используется каждый из них.

Какое объяснение? Пример кода предпочтительнее.

Ответы

Ответ 2

Вот блок-схема, вдохновленная версией Дэвида Мура (см. выше), которую я создал, которая обновлена ​​(в основном) с новым стандартом (С++ 11). Это только мое личное взятие на него, это не бесспорное, но я полагал, что это могло бы быть полезным для этой дискуссии:

enter image description here

Ответ 3

Простой ответ: используйте std::vector для всего, если только у вас нет реальной причины поступить иначе.

Когда вы обнаружите случай, когда вы думаете: "Ну и дела, std::vector не работает здесь хорошо из-за X", иди на основе X.

Ответ 4

Посмотрите на эффективный STL Скотта Мейерса. Это хорошо объясняет, как использовать STL.

Если вы хотите сохранить определенное/неопределенное количество объектов, и вы никогда не удалите их, то вектор - это то, что вы хотите. Это замена по умолчанию для массива C, и она работает как одна, но не переполняется. Вы можете установить его размер заранее, а также с помощью reserve().

Если вы хотите сохранить неопределенное количество объектов, но вы будете добавлять их и удалять, то вам, вероятно, нужен список... потому что вы можете удалить элемент, не перемещая никаких следующих элементов - в отличие от вектора. Это занимает больше памяти, чем вектор, но вы не можете последовательно обращаться к элементу.

Если вы хотите взять кучу элементов и найти только уникальные значения этих элементов, их чтение в набор будет делать это, и оно будет сортировать их для вас.

Если у вас много пар ключ-значение, и вы хотите отсортировать их по ключу, тогда карта полезна... но она будет содержать только одно значение за ключ. Если вам нужно больше одного значения за ключ, вы можете иметь вектор/список в качестве своего значения на карте или использовать мультимап.

Это не в STL, но он находится в обновлении TR1 для STL: если у вас много пар ключ-значение, которые вы собираетесь искать по ключу, и вам не все равно их порядок, вы можете использовать хэш - это tr1:: unordered_map. Я использовал его с Visual С++ 7.1, где он назывался stdext:: hash_map. Он ищет O (1) вместо поиска O (log n) для карты.

Ответ 5

Я переработал блок-схему, чтобы иметь 3 свойства:

  1. Я думаю, что контейнеры STL разделены на 2 основных класса. Основные контейнеры и те используют основные контейнеры для реализации политики.
  2. Сначала блок-схема должна разделить процесс принятия решения на основные ситуации, в которых мы должны принять решение, а затем подробно остановиться на каждом конкретном случае.
  3. Некоторые расширенные контейнеры имеют возможность выбора другого базового контейнера в качестве своего внутреннего контейнера. Блок-схема должна учитывать ситуации, в которых может использоваться каждый из основных контейнеров.

Блок-схема: enter image description here

Более подробная информация предоставлена по этой ссылке.

Ответ 6

Все зависит от того, что вы хотите сохранить и что вы хотите делать с контейнером. Вот некоторые (очень неисчерпывающие) примеры для классов контейнеров, которые я обычно использую больше всего:

vector: Компактная компоновка с небольшими или отсутствующими издержками памяти для каждого содержащегося объекта. Эффективен для повторения. Добавление, вставка и стирание могут быть дорогими, особенно для сложных объектов. Дешево найти содержащийся объект по индексу, например. myVector [10]. Используйте, где бы вы использовали массив в C. Хорошо, где у вас много простых объектов (например, int). Не забудьте использовать reserve() перед добавлением большого количества объектов в контейнер.

list: небольшая нехватка памяти для каждого содержащегося объекта. Эффективен для повторения. Добавлять, вставлять и стирать дешево. Используйте, где бы вы использовали связанный список в C.

setmultiset): значительная служебная нагрузка памяти для каждого содержащегося объекта. Используйте, где вам нужно быстро узнать, если контейнер содержит данный объект или эффективно слить контейнеры.

mapmultimap): Значительные издержки памяти для каждого содержащегося объекта. Используйте, где вы хотите сохранить пары ключ-значение и быстро найти значения по клавишам.

Блок-схема cheat sheet, предложенная zdan, содержит более исчерпывающий справочник.

Ответ 7

Важным моментом, который только кратко упоминается до сих пор, является то, что если вам требуется непрерывная память (например, массив C), вы можете использовать только vector, array или string.

Используйте array, если размер известен во время компиляции.

Используйте string, если вам нужно работать только с типами символов и вам нужна строка, а не только контейнер общего назначения.

Используйте vector во всех остальных случаях (vector должен быть выбором контейнера по умолчанию в любом случае).

Со всеми тремя из них вы можете использовать функцию члена data(), чтобы получить указатель на первый элемент контейнера.

Ответ 8

Один урок, который я усвоил: попытайтесь обернуть его в классе, поскольку изменение типа контейнера в один прекрасный день может принести большие сюрпризы.

class CollectionOfFoo {
    Collection<Foo*> foos;
    .. delegate methods specifically 
}

Это не требует больших затрат и экономит время на отладку, когда вы хотите прервать работу, когда кто-то выполняет операцию x с этой структурой.

Приходя к выбору идеальной структуры данных для работы:

Каждая структура данных предоставляет несколько операций, которые могут быть различной временной сложности:

O (1), O (LG N), O (N) и т.д.

По сути, вам нужно сделать предположение, какие операции будут выполняться чаще всего, и использовать структуру данных, которая имеет эту операцию как O (1).

Просто, не правда ли (-:

Ответ 10

Я ответил на это в другом вопросе, который помечен как дубликат этого. Но я чувствую, что приятно сослаться на некоторые хорошие статьи, касающиеся решения о выборе стандартного контейнера.

Как ответил @David Thornley, std :: vector - это то, что нужно, если нет других особых потребностей. Это совет, данный создателем C++ Бьярном Страуструпом в блоге 2014 года.

Вот ссылка на статью https://isocpp.org/blog/2014/06/stroustrup-lists

и цитата из этого,

И да, я рекомендую использовать std :: vector по умолчанию.

В комментариях пользователь @NathanOliver также предоставляет еще один хороший блог, в котором есть более конкретные измерения. https://baptiste-wicht.com/posts/2012/12/cpp-benchmark-vector-list-deque.html.