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

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

Жанры

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

• контейнер

vector
,
string
и
deque
: используйте идиому
erase/remove_if
;

• контейнер

list
: используйте
list::remove_if
;

• стандартный ассоциативный контейнер: используйте

remove_copy_if/swap
или напишите цикл перебора элементов контейнера, но не забудьте о постфиксном приращении итератора, передаваемого при вызове
erase
.

Дополнительные операции в цикле (кроме удаления объектов):

• стандартный последовательный контейнер: напишите цикл перебора элементов, но не забывайте обновлять итератор значением, возвращаемым

erase
при каждом вызове;

• стандартный ассоциативный контейнер: напишите цикл перебора элементов с постфиксным приращением итератора, передаваемого при вызове

erase
.

Как видите, эффективное удаление элементов контейнера не сводится к простому вызову

erase
. Правильный подход зависит от того, по какому принципу отбираются удаляемые элементы, в каком контейнере они хранятся и какие дополнительные операции требуется выполнить при удалении. Действуйте осторожно и следуйте рекомендациям данного совета, и все будет нормально. Невнимательность обернется неэффективной работой или непредсказуемым поведением программы.

Совет 10. Помните о правилах и ограничениях распределителей памяти

Распределители памяти первоначально разрабатывались как абстракция для моделей памяти, позволяющих разработчикам библиотек игнорировать различия между

near
– и
far
– указателями в некоторых 16-разрядных операционных системах (например, DOS и ее зловредных потомках), однако эта попытка провалилась. Распределители также должны были упростить разработку объектных диспетчеров памяти, но вскоре выяснилось, что такой подход снижает эффективность работы некоторых компонентов STL. Чтобы избежать снижения быстродействия. Комитет по стандартизации C++ включил в Стандарт положение, которое практически выхолостило объектные распределители памяти, но одновременно выражало надежду, что от этой операции их потенциальные возможности не пострадают.

Но это еще не все. Распределители памяти STL, как и

operator new
с
operator new[]
, отвечают за выделение (и освобождение) физической памяти, однако их клиентский интерфейс имеет мало общего с клиентским интерфейсом
operator new
,
operator new[]
и даже
malloc
. Наконец, большинство стандартных контейнеров никогда не запрашивает память у своих распределителей. Еще раз подчеркиваю — никогда. В результате распределители производят довольно странное впечатление.

Впрочем, это не их вина, и, конечно же, из этого факта вовсе не следует делать вывод о бесполезности распределителей. Тем не менее, прежде чем описывать области применения распределителей (эта тема рассматривается в совете 11), я должен объяснить, для чего они не подходят. Существует целый ряд задач, которые только на первый взгляд могут решаться при помощи распределителей. Прежде чем вступать в игру, желательно изучить границы игрового поля, в противном случае вы наверняка упадете и получите травму. Кроме того, из-за экзотических особенностей распределителей сам процесс обобщения выглядит весьма поучительным и занимательным. По крайней мере, я на это надеюсь.

Перечень особенностей распределителей начинается с рудиментарных определений типов для указателей и ссылок. Как упоминалось выше, распределители изначально были задуманы как абстракции для моделей памяти, поэтому казалось вполне логичным возложить на них обеспечение определения типов (

typedef
) для указателей и ссылок в определяемой модели. В стандарте C++ стандартный распределитель объектов типа
T
(
allocator<T>
) предоставляет определения
allocator<T>::pointer
и
allocator<T>::reference
, поэтому предполагается, что пользовательские распределители также будут предоставлять эти определения.

Ветераны C++ немедленно почуют неладное, поскольку в C++ не существует средств для имитации ссылок. Для этого пришлось бы перегрузить

operator.
(оператор «точка»), а это запрещено. Кроме того, объекты, работающие как ссылки, являются примером промежуточных объектов (proxy objects), а использование промежуточных объектов приводит к целому ряду проблем, одна из которых описана в совете 18. Подробное описание промежуточных объектов приведено в совете 30 книги «More Effective C++».

В случае распределителей STL бессмысленность определений типов для указателей и ссылок объясняется не техническими недостатками промежуточных объектов, а следующим фактом: Стандарт разрешает считать, что определение типа

pointer
любого распределителя является синонимом
T*
, а определение типа
reference
— синонимом
T&
. Да, все верно, разработчики библиотек могут игнорировать определения и использовать указатели и ссылки напрямую! Таким образом, даже если вам удастся написать распределитель с новыми определениями для указателей и ссылок, никакой пользы от этого не будет, поскольку используемая реализация STL запросто сможет эти определения проигнорировать. Интересно, не правда ли?

Пока вы не успели осмыслить этот пример странностей стандартизации, я приведу следующий. Распределители являются объектами, из чего следует, что они могут обладать собственными функциями, вложенными типами и определениями типов (такими как

pointer
и
reference
). Однако в соответствии со Стандартом реализация STL может предполагать, что все однотипные объекты распределителей эквивалентны и почти всегда равны. Разумеется, это обстоятельство объяснялось вескими причинами. Рассмотрим следующий фрагмент:

template<typename T> // Шаблон пользовательского

// распределителя памяти

class SpecialAllocator{...};

typedef SpecialAllocator<Widget> SAW; // SAW = "SpecialAllocator

//for Widgets"

list<Widget.SAW> L1;

list<Widget.SAW> L2;

L1.splice(L1.begin, L2);

Вспомните: при перемещении элементов из одного контейнера

list
в другой функцией
splice
данные не копируются. Стоит изменить значения нескольких указателей, и узлы, которые раньше находились в одном списке, оказываются в другом, поэтому операция врезки выполняется быстро и защищена от исключений. В приведенном примере узлы, ранее находившиеся в
L2
, после вызова
splice
перемещаются в
L1
.

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

Личный аптекарь императора. Том 4

Карелин Сергей Витальевич
4. Личный аптекарь императора
Фантастика:
городское фэнтези
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Личный аптекарь императора. Том 4

Барон. Книга вторая

Первухин Андрей Евгеньевич
6. Ученик
Фантастика:
фэнтези
попаданцы
5.40
рейтинг книги
Барон. Книга вторая

Третий Генерал: Тома I-II

Зот Бакалавр
1. Третий Генерал
Фантастика:
городское фэнтези
попаданцы
аниме
сказочная фантастика
5.00
рейтинг книги
Третий Генерал: Тома I-II

Главный рубильник. Расцвет и гибель информационных империй от радио до интернета

Ву Тим
Деловая литература:
о бизнесе популярно
5.00
рейтинг книги
Главный рубильник. Расцвет и гибель информационных империй от радио до интернета

Начало

Харенко Алина Александровна
1. Второй шанс
Фантастика:
фэнтези
5.00
рейтинг книги
Начало

Жизнь, которой не было

Денис Палимов
1. Жизнь, которой не было
Фантастика:
городское фэнтези
аниме
фэнтези
попаданцы
5.00
рейтинг книги
Жизнь, которой не было

Папина дочка

Рам Янка
4. Самбисты
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Папина дочка

Я – Легенда 2: геном хищника

Гарцевич Евгений Александрович
2. Я - Легенда!
Фантастика:
боевая фантастика
рпг
фантастика: прочее
попаданцы
5.00
рейтинг книги
Я – Легенда 2: геном хищника

Кодекс Охотника. Книга XXV

Винокуров Юрий
25. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
6.25
рейтинг книги
Кодекс Охотника. Книга XXV

"Искажающие реальность" Компиляция. Книги 1-14

Атаманов Михаил Александрович
Искажающие реальность
Фантастика:
боевая фантастика
космическая фантастика
киберпанк
рпг
5.00
рейтинг книги
Искажающие реальность Компиляция. Книги 1-14

Проводник

Кораблев Родион
2. Другая сторона
Фантастика:
боевая фантастика
рпг
7.41
рейтинг книги
Проводник

Второй кощей

Билик Дмитрий Александрович
8. Бедовый
Фантастика:
юмористическое фэнтези
городское фэнтези
мистика
5.00
рейтинг книги
Второй кощей

Пески веков (сборник)

Уиндем Джон Паркс Лукас Бейнон Харрис
1970. Зарубежная фантастика
Фантастика:
научная фантастика
5.00
рейтинг книги
Пески веков (сборник)

Возвращение

Кораблев Родион
5. Другая сторона
Фантастика:
боевая фантастика
6.23
рейтинг книги
Возвращение