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

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

Жанры

Эффективное использование 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
с подсчетом ссылок в многопоточной среде желательно следить за проблемами быстродействия, обусловленными поддержкой потоковой безопасности.

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

Дракон с подарком

Суббота Светлана
3. Королевская академия Драко
Любовные романы:
любовно-фантастические романы
6.62
рейтинг книги
Дракон с подарком

Бывшие. Война в академии магии

Берг Александра
2. Измены
Любовные романы:
любовно-фантастические романы
7.00
рейтинг книги
Бывшие. Война в академии магии

Мастер клинков. Начало пути

Распопов Дмитрий Викторович
1. Мастер клинков
Фантастика:
фэнтези
9.16
рейтинг книги
Мастер клинков. Начало пути

Имя нам Легион. Том 8

Дорничев Дмитрий
8. Меж двух миров
Фантастика:
боевая фантастика
рпг
аниме
5.00
рейтинг книги
Имя нам Легион. Том 8

Измена. Право на счастье

Вирго Софи
1. Чем закончится измена
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Измена. Право на счастье

Начальник милиции 2

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

Камень. Книга 4

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

Измена. Мой заклятый дракон

Марлин Юлия
Любовные романы:
любовно-фантастические романы
7.50
рейтинг книги
Измена. Мой заклятый дракон

Предатель. Цена ошибки

Кучер Ая
Измена
Любовные романы:
современные любовные романы
5.75
рейтинг книги
Предатель. Цена ошибки

Звездная Кровь. Изгой

Елисеев Алексей Станиславович
1. Звездная Кровь. Изгой
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Звездная Кровь. Изгой

Рождение победителя

Каменистый Артем
3. Девятый
Фантастика:
фэнтези
альтернативная история
9.07
рейтинг книги
Рождение победителя

Барону наплевать на правила

Ренгач Евгений
7. Закон сильного
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Барону наплевать на правила

Камень. Книга шестая

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

Чужая дочь

Зика Натаэль
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Чужая дочь