Чтение онлайн

на главную - закладки

Жанры

Эффективное использование STL
Шрифт:

vector<int> v;

{ // Создание нового блока

 Lock<vector<int> > lock(v); // Получение мьютекса

 vector<int>::iterator first5(find(v.begin, v.end, 5));

 if (first5 != v.end) {

*first5 = 0;

 }

} // Закрытие блока с автоматическим

// освобождением мьютекса

Поскольку мьютекс контейнера освобождается в деструкторе

Lock
, важно обеспечить
уничтожение
Lock
сразу же после освобождения мьютекса. Для этого мы создаем новый блок, в котором определяется объект
Lock
, и закрываем его, как только надобность в мьютексе отпадает. На первый взгляд кажется, что вызов
releaseMutexFor
попросту заменен необходимостью закрыть блок, но это не совсем так. Если мы забудем создать новый блок для
Lock
, мьютекс все равно будет освобожден, но это может произойти позднее положенного момента — при выходе из внешнего блока. Если забыть о вызове
releaseMutexFor
, мьютекс вообще не освобождается.

Более того, решение, основанное на классе

Lock
, лучше защищено от исключений. C++ гарантирует уничтожение локальных объектов при возникновении исключения, поэтому
Lock
освободит мьютекс, даже если исключение произойдет при использовании объекта
Lock
. При использовании парных вызовов
getMutexFor/releaseMutexFor
мьютекс не будет освобожден, если исключение происходит после вызова
getMutexFor
, но перед вызовом
releaseMutexFor
.

Исключения и управление ресурсами важны, но данный совет посвящен другой теме — потоковой безопасности в STL. Как говорилось выше, вы можете надеятьсяна то, что реализация библиотеки обеспечивает параллельное чтение из одного контейнера и одновременную запись в разные контейнеры. Не надейтесь, что библиотека избавит вас от ручной синхронизации и не рассчитывайте на поддержку многопоточности.

Контейнеры vector и string

Все контейнеры STL по-своему полезны, однако большинство программистов C++ работает с

vector
и string чаще, чем с их собратьями, и это вполне понятно. Ведь контейнеры
vector
и
string
разрабатывались как замена массивов, а массивы настолько полезны и удобны, что встречаются во всех коммерческих языках программирования от COBOL до Java.

В этой главе контейнеры

vector
и
string
рассматриваются с нескольких точек зрения. Сначала мы разберемся, чем они превосходят классические массивы STL, затем рассмотрим пути повышения быстродействия
vector
и
string
, познакомимся с различными вариантами реализации
string
, изучим способы передачи
string
и
vector
функциям API, принимающим данные в формате C. Далее будет показано, как избежать лишних операций выделения памяти. Глава завершается анализом поучительной аномалии,
vector<bool>
.

Совет 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<char>
выгладит вполне разумно. Контейнеры
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++ специально разрешил ее использование.

Впрочем, оптимизация нередко оборачивается «пессимизацией». При использовании

string
с подсчетом ссылок в многопоточной среде время, сэкономленное на выделении памяти и копировании, может оказаться ничтожно малым по сравнению со временем, затраченным на синхронизацию доступа (за подробностями обращайтесь к статье Саттера «Optimizations That Aren't (In a Multithreaded World)» [20]). Таким образом, при использовании
string
с подсчетом ссылок в многопоточной среде желательно следить за проблемами быстродействия, обусловленными поддержкой потоковой безопасности.

Поделиться:
Популярные книги

Жена проклятого некроманта

Рахманова Диана
Фантастика:
фэнтези
6.60
рейтинг книги
Жена проклятого некроманта

Сын Тишайшего

Яманов Александр
1. Царь Федя
Фантастика:
попаданцы
альтернативная история
фэнтези
5.20
рейтинг книги
Сын Тишайшего

Демон

Парсиев Дмитрий
2. История одного эволюционера
Фантастика:
рпг
постапокалипсис
5.00
рейтинг книги
Демон

30 сребреников

Распопов Дмитрий Викторович
1. 30 сребреников
Фантастика:
попаданцы
альтернативная история
фэнтези
фантастика: прочее
5.00
рейтинг книги
30 сребреников

Небо в огне. Штурмовик из будущего

Политов Дмитрий Валерьевич
Военно-историческая фантастика
Фантастика:
боевая фантастика
7.42
рейтинг книги
Небо в огне. Штурмовик из будущего

Осознание. Пятый пояс

Игнатов Михаил Павлович
14. Путь
Фантастика:
героическая фантастика
5.00
рейтинг книги
Осознание. Пятый пояс

Камень

Минин Станислав
1. Камень
Фантастика:
боевая фантастика
6.80
рейтинг книги
Камень

Блокада. Знаменитый роман-эпопея в одном томе

Чаковский Александр Борисович
Проза:
военная проза
7.00
рейтинг книги
Блокада. Знаменитый роман-эпопея в одном томе

Цикл "Отмороженный". Компиляция. Книги 1-14

Гарцевич Евгений Александрович
Отмороженный
Фантастика:
боевая фантастика
рпг
постапокалипсис
5.00
рейтинг книги
Цикл Отмороженный. Компиляция. Книги 1-14

Книга 4. Игра Кота

Прокофьев Роман Юрьевич
4. ОДИН ИЗ СЕМИ
Фантастика:
фэнтези
боевая фантастика
рпг
6.68
рейтинг книги
Книга 4. Игра Кота

Мастер 2

Чащин Валерий
2. Мастер
Фантастика:
фэнтези
городское фэнтези
попаданцы
технофэнтези
4.50
рейтинг книги
Мастер 2

Новый Рал 2

Северный Лис
2. Рал!
Фантастика:
фэнтези
7.62
рейтинг книги
Новый Рал 2

Низший 2

Михайлов Дем Алексеевич
2. Низший!
Фантастика:
боевая фантастика
7.07
рейтинг книги
Низший 2

Под маской, или Страшилка в академии магии

Цвик Катерина Александровна
Фантастика:
юмористическая фантастика
7.78
рейтинг книги
Под маской, или Страшилка в академии магии