контейнере, гарантированно находятся рядом и в памяти, что не гарантирует ни один другой контейнер.
• Гарантирует совместимость размещения в памяти с размещением, используемым языком программирования С, в отличие от остальных стандартных контейнеров (см. рекомендации 77 и 78).
• Гарантирует наличие самых гибких итераторов (произвольного доступа).
• Почти гарантированно имеет самые быстрые итераторы (указатели или классы со сравнимой производительностью, которые зачастую работают в окончательной (не отладочной) версии с той же скоростью, что и указатели).
vector
и спокойно работайте, зная, что вы сделали верный выбор.
И последнее — лучше использовать контейнеры и алгоритмы стандартной библиотеки, а не стороннего производителя или разработанные самостоятельно.
list
только потому, что 'очевидно, что list
—подходящий тип для выполнения операций со списком', таких как вставка в средину последовательности. Тип vector
для небольших списков практически всегда превосходит тип list
. Несмотря на то, что вставка в средину последовательности требует линейного времени работы у vector
, и постоянного — у list
, вектор с небольшим количеством элементов обычно справляется с этой задачей быстрее — за счет меньшего постоянного множителя; преимущества асимптотического времени работы list
проявляются только при больших количествах элементов в контейнере.
Таким образом, используйте vector
, пока размеры данных не потребуют иного выбора (см. рекомендацию 7), либо пока не станет существенной обеспечение строгой гарантии безопасности при возможной генерации исключений копирующим конструктором или копирующим оператором присваивания типа объектов, хранящихся в контейнере. В последнем случае может оказаться важным, что контейнер list
обеспечивает строгую гарантию безопасности для операции вставки в коллекцию таких типов.
77. Вместо массивов используйте vector
и string
Избегайте реализации абстракция массива посредством массивов в стиле С, арифметики указателей и примитивов управления памятью. Использование vector
или string
не только сделает проще вашу жизнь, но и позволит написать более безопасную и масштабируемую программу.
Сегодня едва ли не основными вопросами при написании программного обеспечения являются вопросы безопасности и переполнения буфера. Ограничения, связанные с фиксированным размером массивов, доставляют немало беспокойства, даже если приложению удается остаться в рамках корректности. Все эти проблемы связаны с использованием старых средств С, таких как встроенные массивы, указатели и их арифметика, а также управление памятью вручную вместо таких высокоуровневых концепций, как буферы, векторы и строки.
Вот некоторые из причин, по которым массивам в стиле С следует предпочесть стандартные средства С++.
• reallос
и соответствующих обновлений указателей.
•
• vector
и string::c_str
могут быть переданы функциям API на языке С. В частности, в С++ vector
служит 'переходником' к С и другим языкам программирования (см. рекомендации 76 и 78).
•
• vector
и string
при выборе между эффективностью и безопасностью решение принимается в пользу эффективности (естественно, не в отладочном режиме). Тем не менее, стандартные средства оказываются гораздо лучшей платформой для создания безопасных компонентов, чем обычные массивы и указатели.
•
Применение массива может быть оправданно, когда его размер фиксирован на стадии компиляции (например, float[3]
для трехмерной точки; переход к четвертому измерению все равно потребует перепроектирования программы).
78. Используйте vector
(и string::c_str
) для обмена данными с API на других языках
vector
и string::c_str
служат шлюзом для сообщения с API на других языках. Однако не полагайтесь на то, что итераторы являются указателями; для получения адреса элемента, на который ссылается vector<T>::iterator iter
, используйте выражение &*iter
.
vector
(в первую очередь) и string::c_str
и string::data
(во вторую) представляют собой наилучшие способы обмена данными с API на других языках вообще и с библиотеками на С в частности.
Данные vector
всегда хранятся последовательно, так что получение адреса первого элемента вектора дает указатель на его содержимое. Используйте &*v.begin()
, &v[0]
или &v.front()
для получения указателя на первый элемент