Исключения и управление ресурсами важны, но данный совет посвящен другой теме — потоковой безопасности в STL. Как говорилось выше, вы можете надеяться на то, что реализация библиотеки обеспечивает параллельное чтение из одного контейнера и одновременную запись в разные контейнеры. Не надейтесь, что библиотека избавит вас от ручной синхронизации и не рассчитывайте на поддержку многопоточности.
Контейнеры vector и string
Все контейнеры STL по-своему полезны, однако большинство программистов C++ работает с vector
и string чаще, чем с их собратьями, и это вполне понятно. Ведь контейнеры vector
и string
разрабатывались как замена массивов, а массивы настолько полезны и удобны, что встречаются во всех коммерческих языках программирования от COBOL до Java.
В этой главе контейнеры vector
и string
рассматриваются с нескольких точек зрения. Сначала мы разберемся, чем они превосходят классические массивы STL, затем рассмотрим пути повышения быстродействия vector
и string
, познакомимся с различными вариантами реализации string
, изучим способы передачи string
и vector
функциям API, принимающим данные в формате C. Далее будет показано, как избежать лишних операций выделения памяти. Глава завершается анализом поучительной аномалии, vector
.
Совет 13. Используйте vector и string вместо динамических массивов
Принимая решение о динамическом выделении памяти оператором new
, вы берете на себя ряд обязательств.
1. Выделенная память в дальнейшем должна быть освобождена оператором delete
. Вызов new
без последующего delete
приводит к утечке ресурсов.
2. Освобождение должно выполняться соответствующей формой оператора delete
. Одиночный объект освобождается простым вызовом delete
, а для массивов требуется форма delete[]
. Ошибка в выборе формы delete
приводит к непредсказуемым последствиям. На одних платформах программа «зависает» во время выполнения, а на других она продолжает работать с ошибками, приводящими к утечке ресурсов и порче содержимого памяти.
3. Оператор delete
для освобождаемого объекта должен вызываться ровно один раз. Повторное освобождение памяти также приводит к непредсказуемым последствиям.
Итак, динамическое выделение памяти сопряжено с немалой ответственностью, и я не понимаю, зачем брать на себя лишние обязательства. При использовании vector
и string
необходимость в динамическом выделении памяти возникает значительно реже.
Каждый раз, когда вы готовы прибегнуть к динамическому выделению памяти под массив (то есть собираетесь включить в программу строку вида « new T[…]
»), подумайте, нельзя ли вместо этого воспользоваться vector
или string
. Как правило, string
используется в том случае, если T
является символьным типом, а vector
— во всех остальных случаях. Впрочем, позднее мы рассмотрим ситуацию, когда выбор vector
выгладит вполне разумно. Контейнеры vector
и string
избавляют программиста от хлопот, о которых говорилось выше, поскольку они самостоятельно управляют своей памятью. Занимаемая ими память расширяется по мере добавления новых элементов, а при уничтожении vector
или string
деструктор автоматически уничтожает элементы контейнера и освобождает память, в которой они находятся.
Кроме того, vector
и string
входят в семейство последовательных контейнеров STL, поэтому в вашем распоряжении оказывается весь арсенал алгоритмов STL, работающих с этими контейнерами. Впрочем, алгоритмы STL могут использоваться и с массивами, однако у массивов отсутствуют удобные функции begin
, end
, size
и т. п., а также вложенные определения типов ( iterator ,reverse_iterator ,value_type
и т. д.), а указатели char*
вряд ли могут сравниться со специализированными функциями контейнера string
. Чем больше работаешь с STL, тем меньше энтузиазма вызывают встроенные массивы.
Если вас беспокоит судьба унаследованного кода, работающего с массивами, не волнуйтесь и смело используйте vector
и string
. В совете 16 показано, как легко организовать передачу содержимого vector
и string
функциям C, работающим с массивами, поэтому интеграция с унаследованным кодом обычно обходится без затруднений.
Честно говоря, мне приходит в голову лишь одна возможная проблема при замене динамических массивов контейнерами vector/string
, причем она относится только к string
. Многие реализации string
основаны на подсчете ссылок (совет 15), что позволяет избавиться от лишних выделений памяти и копирования символов, а также во многих случаях ускоряет работу контейнера. Оптимизация string
на основе подсчета ссылок была сочтена настолько важной, что Комитет по стандартизации C++ специально разрешил ее использование.
Читать дальше