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

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

Жанры

C++. Сборник рецептов

Когсуэлл Джефф

Шрифт:

Метод

insert
предоставляет альтернативный метод добавления пар в отображение,
insert
выполняет строгую вставку, а не вставку/обновление, как
operator[]
. При использовании map (но не
multimap
, который может содержать дублирующиеся ключи)
insert
, если ключ уже существует, не делает ничего. По сравнению с ним
operator[]
, если ключ уже существует, заменяет значение объекта для этого ключа на новое.

Но синтаксис вставки требует несколько большей работы, чем

operator[]
, и он связан с тем, как
map
хранит данные. Рассмотрим строку из примера 6.6.

strMap.insert(std::make_pair("Sunday", "Sonntag"));

ma

p
хранит пары ключ/значение
в объекте
pair
,
pair
— это простой вспомогательный шаблон класса (объявленный в
<utility>
и включенный в
<map>
), который хранит два значения двух типов. Чтобы объявить
pair
из двух
string
, сделайте так.

pair<string, string> myPair;

Первый и второй элементы в

pair
доступны по открытым членам
first
и
second
. При использовании для доступа к элементам
map
оператора
operator[]
обычно работать с
pair
не приходится, но в случае со многими другими методами это придется делать, так что следует знать, как создавать и использовать объекты
pair
. Например, итераторы разыменовываются в простые объекты
pair
, так что при их использовании, как это делается в примере 6.6, следует знать, как получить ключ и его значение.

for (map<string, string> iterator p = strMap.begin;

 p != strMap.end; ++p)

 cout << "English: " << p->first

<< ", German: " << p->second << endl;

Ключ хранится в

first
, а значение хранится в
second
.

Однако это не объясняет, почему я использовал

make_pair
.
make_pair
— это вспомогательный шаблон функции, который создает объект
pair
на основе двух переданных в него аргументов. Некоторые предпочитают этот подход вызову конструктора
pair
, так как шаблон класса не может догадаться о типах своих аргументов, в то время как шаблон функции может. Таким образом, эти две строки кода функционально эквивалентны.

strMap.insert(std::make_pair("Sunday", "Sonntag"));

strMap.insert(std::pair<string, string>("Sunday", "Sonntag"));

map
не допускает наличия дублирующихся ключей. Если требуется разрешить дублирование ключей, следует использовать
multimap
, который является
map
, разрешающим наличие несколько одинаковых ключей. Его интерфейс идентичен
map
, но поведение методов в необходимых случаях отличается. В табл. 6.1 приведен перечень методов, которые есть в одном, но отсутствуют в другом, и пояснения различий в поведении общих методов, map и
multimap
содержат несколько
typedef
, которые описывают различные значения, хранящиеся в них. В табл. 6.1 они используются следующим образом:

key_type

Это тип ключа. В

string map,
объявленном как
map<string, MyClass*>
,
key_type
должен быть
string
.

mapped_type

Это тип значения, на которое отображается ключ. В

string map
, объявленном как
map<string, MyClass*>
,
mapped_type
должен быть
MyClass*
.

value_type

Это тип объекта, содержащего ключ и значение, которой, применительно к

map
и
multimap
, является
pair<const key_type, mapped_type>
.

Табл. 6.1. map и multimap

Метод map, multimap или оба Поведение
T& operator[] (const key_type& k)
map
Возвращает ссылку на объект значения, сохраненный с ключом
k
. Если
k
в map отсутствует, то он добавляется, а объект значения создается с помощью конструктора по умолчанию
iterator insert(const value_type& v) pair<iterator, bool> insert(const value_type& v)
Оба Первая версия вставляет
v
в
multimap
и возвращает итератор, который указывает на вставленную пару
pair
. Вторая версия вставляет
v
и
map
при условии, что в
map
еще не содержится ключа, равного
v
. Возвращаемая
pair
содержит итератор который указывает на вставленную
pair
, если произошла вставка, и
bool
, указывающий, была ли вставка успешной
iterator find(const key_type& k)
Оба Возвращает итератор или
const_iterator
, который указывает на
mapped_type
, соответствующий
k
. В
multimap
не гарантируется, что возвращаемый итератор будет указывать на первое значение, соответствующее
k
. Если ключа, равного k, нет, то возвращаемый итератор равен
end

Также табл 6.1 показывает разницу в поведении между

map
и
multimap
.

Если

operator[]
вам не подходит, т.е. другой способ найти ключ в
map
. Для этого можно использовать метод
find
.

map<string, string>::const_iterator p

 = strMap.find("Thursday");

if (p != strMap.end)

 cout << "Thursday = " << p->second << endl;

Но не забудьте, что при использовании

multimap
не гарантируется, что возвращаемый элемент будет первым элементом с ключом, равным искомому. Если нужен первый элемент, чей ключ не меньше определенного значения или не больше определенного значения, используйте
lower_bound
или
upper_bound
.
lower_bound
возвращает итератор, указывающий на первую пару ключ/значение, равную или большую, чем аргумент
key_type
. Другими словами, если ваш
map
содержит дни недели, как в примере 6.6, следующий код вернет итератор, который указывает на пару, содержащую
"Friday"
и
"Freitag"
.

p = strMap.lower_bound("Foo");

if (p != strMap.end)

 cout << p->first << " = " << p->second << endl;

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

"Foo"
.
upper_bound
работает аналогично, но с противоположным условием.

В начале этого обсуждения я упоминал, что элементы в map хранятся в отсортированном по ключам порядке, так что при переборе от

begin
до
end
каждый элемент будет «больше», чем предшествующий (а в
multimap
— больше или равен ему) Но при использовании более сложных ключей, чем
string
или числа, может потребоваться указать, как при вставке элементов в отображение следует сравнивать ключи.

По умолчанию ключи хранятся с помощью стандартного функтора

less
(объявленного в
<functional>
).
less
— это двоичная функция (принимает два аргумента одинакового типа), которая возвращает
bool
, указывающий на то, больше ли первый аргумент, чем второй, или нет. Другими словами,
less(a, b)
возвращает
a < b
. Если это не то, что вам требуется, создайте свой собственный функтор и объявите
map
с его помощью. Например, если в качестве ключа используется объект
Person
и каждый
Person
имеет имя и фамилию, то может потребоваться сравнивать фамилии и имена. Пример 6.7 показывает способ сделать это.

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

Попаданка 3

Ахминеева Нина
3. Двойная звезда
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Попаданка 3

Ученик. Книга третья

Первухин Андрей Евгеньевич
3. Ученик
Фантастика:
фэнтези
7.64
рейтинг книги
Ученик. Книга третья

Два лика Ирэн

Ром Полина
Любовные романы:
любовно-фантастические романы
6.08
рейтинг книги
Два лика Ирэн

Одержимый

Поселягин Владимир Геннадьевич
4. Красноармеец
Фантастика:
боевая фантастика
5.00
рейтинг книги
Одержимый

Испытание Огня

Гаврилова Анна Сергеевна
3. Академия Стихий
Фантастика:
фэнтези
9.43
рейтинг книги
Испытание Огня

Измена. Возвращение любви!

Леманн Анастасия
3. Измены
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Измена. Возвращение любви!

An ordinary sex life

Астердис
Любовные романы:
современные любовные романы
love action
5.00
рейтинг книги
An ordinary sex life

Миф об идеальном мужчине

Устинова Татьяна Витальевна
Детективы:
прочие детективы
9.23
рейтинг книги
Миф об идеальном мужчине

Девятый

Каменистый Артем
1. Девятый
Фантастика:
боевая фантастика
попаданцы
9.15
рейтинг книги
Девятый

Невеста клана

Шах Ольга
Фантастика:
попаданцы
фэнтези
5.00
рейтинг книги
Невеста клана

В семье не без подвоха

Жукова Юлия Борисовна
3. Замуж с осложнениями
Фантастика:
социально-философская фантастика
космическая фантастика
юмористическое фэнтези
9.36
рейтинг книги
В семье не без подвоха

Возвышение Меркурия. Книга 15

Кронос Александр
15. Меркурий
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Возвышение Меркурия. Книга 15

Его огонь горит для меня. Том 2

Муратова Ульяна
2. Мир Карастели
Фантастика:
юмористическая фантастика
5.40
рейтинг книги
Его огонь горит для меня. Том 2

Младший сын князя

Ткачев Андрей Сергеевич
1. Аналитик
Фантастика:
фэнтези
городское фэнтези
аниме
5.00
рейтинг книги
Младший сын князя