Читать «Стандарты программирования на С++. 101 правило и рекомендация» онлайн - страница 122

Андрей Александреску

76. По умолчанию используйте vector. В противном случае выбирайте контейнер, соответствующий задаче

Резюме

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

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

Обсуждение

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

• Следует писать в первую очередь корректный, простой и понятный код (см. рекомендацию 6). Предпочтителен выбор контейнера, который позволит вам написать наиболее понятный код. Так, если вам требуется вставка в определенную позицию, используйте последовательный контейнер (например, vector, list). Если вам нужен итератор произвольного доступа, выберите vector, deque или string. Если нужен словарный поиск наподобие c[0]=42;, воспользуйтесь ассоциативным контейнером (например, set, map) — но если вам требуется упорядоченная ассоциативная коллекция, то вы не можете использовать контейнеры с использованием хеширования (нестандартные hash_… или стандартные unordered_… контейнеры).

• Вопросы эффективности при написании должны учитываться только тогда и там, где это действительно необходимо (см. рекомендацию 8). Если на основании проведенных измерений с реальными данными доказано, что скорость поиска действительно критична, можно воспользоваться контейнерами с использованием хеширования (нестандартными hash_… или стандартными unordered_… контейнерами), затем — отсортированным vector, затем — set или map, обычно в приведенном порядке. Даже в этой ситуации отличия асимптотического времени работы (с использованием "большого O", например, линейное и логарифмическое время работы; см. рекомендацию 7) имеет значение, только если контейнеры достаточно велики, чтобы постоянные множители перестали играть роль. Для контейнеров, содержащих небольшие объекты наподобие double, для преодоления влияния постоянных множителей обычно требуется по крайней мере несколько тысяч элементов.

• Там, где это возможно и разумно, лучше писать транзакционный код со строгой гарантией безопасности код (см. рекомендацию 71), и не использовать некорректные объекты (см. рекомендацию 99). Если для вставки и удаления элементов вам требуется транзакционная семантика, или если необходимо минимизировать недействительность итераторов, лучше воспользоваться контейнерами на основе узлов (например, list, set, map).

В противном случае следуйте совету Стандарта: "vector представляет собой тип последовательности, который нужно использовать по умолчанию" ([C++03] §23.1.1).

Если вы сомневаетесь в данном совете, спросите сами себя — действительно ли у вас есть непреодолимые причины не использовать стандартный контейнер vector, который обладает следующими свойствами.