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

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

Жанры

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

Контейнер

map
эмулируется на базе сортированного вектора практически так же, как и контейнер
set
. Единственное принципиальное отличие заключается в том, что в качестве функций сравнения используются объекты
DataCompare
:

vector<Widget> vd; // Альтернатива для map<string, int>

… // Подготовительная фаза: много вставок,

// мало операций поиска

sort(vd.begin, vd.end, DataCompare); // Конец подготовительной фазы

// (при эмуляции multiset можно

//
воспользоваться алгоритмом

// stable_sort - см. совет 31)

string s; // Объект с искомым значением

… // Начало фазы поиска

if (binary_search(vd.begin, vd.end, s, DataCompare))… // Поиск

// с применением binary_search

vector<Data>::iterator i = lower_bound(vd.begin, vd.end.s,

 DataCompare); // Поиск с применением

if (i != vd.end && !(i->first < s))… // lower_bound: конструкция

//!(i->first<s)) описана

//в совете 45

pair<vector<Data>::iterator, vector<Data>::iterator> range =

 equal_range(vd.begin, vd.end, s, DataCompare); // Поиск с применением

if (range.first != range.second)… // equal_range

… // Конец фазы поиска,

// начало фазы реорганизации

sort(vd.begin, vd.end, DataCompare); //Начало новой фазы поиска…

Как видите, после написания

DataCompare
все более или менее становится на свои места. Показанное решение часто быстрее работает и расходует меньше памяти, чем аналогичная архитектура с настоящим контейнером
map
— при условии, что операции со структурой данных в вашей программе делятся на фазы, описанные на с. 99. Если подобное деление на фазы не соблюдается, использование сортированного вектора вместо стандартных ассоциативных контейнеров почти всегда оборачивается напрасной тратой времени.

Совет 24. Тщательно выбирайте между map::operator[] и map::insert

Допустим, у нас имеется класс

Widget
с конструктором по умолчанию, а также конструктором и оператором присваивания с операндом типа double:

class Widget {

public:

 Widget;

 Widget(double weight);

 Widget& operator=(double weight);

 …

};

Предположим, мы хотим создать контейнер

map
, ассоциирующий
int
с
Widget
, и инициализировать созданное множество конкретными значениями. Все выглядит очень просто:

map<int, Widget> m;

m[1]=1.50;

m[2]=3.67;

m[3]=10.5;

m[4]=45.8;

m[5]=0.0003;

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

Функция

operator[]
контейнеров
map
никак не связана с функциями
operator[]
контейнеров
vector
,
deque
и
string
, а также со встроенным оператором
[]
, работающим с массивами. Функция
map::operator[]
упрощает операции «обновления с возможным созданием». Иначе говоря, при наличии объявления
map<K, V> m
команда
m[k]=v;
проверяет, присутствует ли ключ 
k
в контейнере. Если ключ отсутствует, он добавляется вместе с ассоциированным значением
v
. Если ключ уже присутствует, ассоциированное с ним значение заменяется на
v
.

Для этого

operator[]
возвращает ссылку на объект значения, ассоциированного с ключом
k
, после чего v присваивается объекту, к которому относится эта ссылка. При обновлении значения, ассоциированного с существующим ключом, никаких затруднений не возникает — в контейнере уже имеется объект, ссылка на который возвращается функцией
operator[]
. Но при отсутствии ключа 
k
готового объекта, на который можно было бы вернуть ссылку, не существует. В этом случае объект создается конструктором по умолчанию, после чего
operator[]
возвращает ссылку на созданный объект.

Вернемся к началу исходного примера:

map<int, Widget> m;

m[1]=1.50;

Выражение

m[1]
представляет собой сокращенную запись для
m.operator[](1)
, поэтому во второй строке присутствует вызов
map::operator[]
. Функция должна вернуть ссылку на ассоциированный объект
Widget
. В данном примере
m
еще не содержит ни одного элемента, поэтому элемент с ключом 1 не существует. Конструктор по умолчанию создает объект
Widget
, ассоциируемый с ключом 1, и возвращает ссылку на этот объект. Наконец, созданному объекту
Widget
присваивается значение 1.50.

Иначе говоря, команда

m[1]=1.50:

функционально эквивалентна следующему фрагменту:

typedef map<int, Widget> intWidgetMap; // Вспомогательное определение типа

pair<intWidgetMap::iterator, bool> result = // Создание нового

 m.insert(intWidgetMap::value_type(1, Widget)); // элемента с ключом 1

// и ассоциированным объектом, созданным

// конструктором по умолчанию; комментарии

// по поводу value_type

// приведены далее

result.first->second = 1.50; // Присваивание значения

// созданному объекту

Теперь понятно, почему такой подход ухудшает быстродействие программы. Сначала мы конструируем объект

Widget
, а затем немедленно присваиваем ему новое значение. Конечно, правильнее было бы сразу сконструировать
Widget
с нужными данными вместо того, чтобы конструировать
Widget
по умолчанию и затем выполнять присваивание. Следовательно, вызов
operator[]
было бы правильнее заменить прямолинейным вызовом
insert
:

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

Хранилище

Старухин Евгений
5. Лесовик
Фантастика:
фэнтези
рпг
7.43
рейтинг книги
Хранилище

Морской волк. 1-я Трилогия

Савин Владислав
1. Морской волк
Фантастика:
альтернативная история
8.71
рейтинг книги
Морской волк. 1-я Трилогия

Искатель 1

Шиленко Сергей
1. Валинор
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Искатель 1

Анти-Ксенонская Инициатива

Вайс Александр
7. Фронтир
Фантастика:
боевая фантастика
космическая фантастика
космоопера
5.00
рейтинг книги
Анти-Ксенонская Инициатива

На границе империй. Том 10. Часть 8

INDIGO
Вселенная EVE Online
Фантастика:
боевая фантастика
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 10. Часть 8

Мастер решений

Земляной Андрей Борисович
3. Специалист по выживанию
Фантастика:
боевая фантастика
космическая фантастика
6.20
рейтинг книги
Мастер решений

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

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

Хозяин Теней

Петров Максим Николаевич
1. Безбожник
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Хозяин Теней

Последний реанорец. Том IX

Павлов Вел
8. Высшая Речь
Фантастика:
фэнтези
попаданцы
аниме
5.75
рейтинг книги
Последний реанорец. Том IX

Я до сих пор князь. Книга XXII

Дрейк Сириус
22. Дорогой барон!
Фантастика:
юмористическое фэнтези
аниме
попаданцы
5.00
рейтинг книги
Я до сих пор князь. Книга XXII

Источник

Билик Дмитрий Александрович
11. Бедовый
Фантастика:
юмористическое фэнтези
городское фэнтези
мистика
7.00
рейтинг книги
Источник

Неучтенный элемент. Том 10

NikL
10. Антимаг. Вне системы
Фантастика:
фэнтези
5.00
рейтинг книги
Неучтенный элемент. Том 10

Последний Паладин. Том 13

Саваровский Роман
13. Путь Паладина
Фантастика:
городское фэнтези
попаданцы
аниме
5.00
рейтинг книги
Последний Паладин. Том 13

Дитя прибоя

Трофимов Ерофей
Дитя прибоя
Фантастика:
боевая фантастика
попаданцы
фэнтези
5.00
рейтинг книги
Дитя прибоя