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

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

Жанры

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

Сказанное прежде всего касается контейнеров

map
и
multimap
, поскольку программы, пытающиеся изменить значение ключа в этих контейнерах, не будут компилироваться:

map<int, string> m;

m.begin->first = 10; // Ошибка! Изменение ключей

// в контейнере map запрещено

multimap<int, string> mm;

mm.begin->first = 20; // Ошибка! Изменение ключей

// в контейнере multimap запрещено

Дело в том, что элементы объекта типа

map<K, V>
или
multimap<K, V>
относятся к типу
pair<const K, V>
. Ключ относится к типу
const K
и поэтому не может изменяться. Впрочем, его все же можно изменить с применением
const_cast
, как показано ниже. Хотите — верьте, хотите — нет, но иногда это даже нужно.

Обратите внимание: в заголовке этого совета ничего не сказано о контейнерах 

map
и
multimap
. Для этого есть веские причины. Как показывает предыдущий пример, модификация ключа «на месте» невозможна для
map
и
multimap
(без применения преобразования
const_cast
), но может быть допустима для
set
и
multiset
. Для объектов типа
set<T>
и
multiset<T>
в контейнере хранятся элементы типа
T
, а не
const T
. Следовательно, элементы контейнеров
set
и mu
l
tiset можно изменять в любое время, и преобразование
const_cast
для этого не требуется (вообще говоря, дело обстоит не так просто, но не будем забегать вперед).

Сначала выясним, почему элементы

set
и
multiset
не имеют атрибута
const
. Допустим, у нас имеется класс
Employee
:

class Employee {

public:

 …

 const string& name const; // Возвращает имя работника

 void setName(const string& name); // Задает имя работника

 const string& title const; // Возвращает должность

 void setTitle(const string& title); // Задает должность

 int idNumber const; // Возвращает код работника

 …

}

Объект содержит разнообразные сведения о работнике. Каждому работнику назначается уникальный код, возвращаемый функцией

idNumber
. При создании контейнера
set
с объектами
Employee
было бы вполне разумно упорядочить его по кодам работников:

struct IDNumberLess:

 public binary_function<Employee, Employee, bool> { // См. совет 40

 bool operator (const Employees lhs, const Employees rhs) const {

return lhs.idNumber < rhs. IdNumber;

 }

}

typedef set<Employee, IDNumberLess> EmplIDSet;

EmplIDSet se; // Контейнер set объектов

// Employee, упорядоченных

// по коду

С практической точки зрения код работника является ключомдля элементов данного множества, а остальные данные вторичны. Учитывая это обстоятельство, ничто не мешает перевести работника на более интересную должность. Пример:

Employee selectedID; // Объект работника с заданным кодом

EmpIDSet::iterator = se.find(selectedID);

if (i!=se.end) {

 i->setTitle("Corporate Deity"); // Изменить должность

}

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

Спрашивается, почему нельзя применить ту же логику к ключам контейнеров

map
и
multimap
? Почему бы не создать контейнер
map
, ассоциирующий работников со страной, в которой они живут; контейнер с функцией сравнения
IDNumberLess
, как в предыдущем примере? И почему бы в таком контейнере не изменить должность без изменения кода работника, как в предыдущем примере?

Откровенно говоря, мне это кажется вполне логичным, однако мое личное мнение в данном случае несущественно. Важно то, что Комитет по стандартизации решил, что ключи

map/multimap
должны быть неизменными (
const
), а значения
set/multiset
— не должны.

Значения в контейнерах

set/multiset
не являются неизменными, поэтому попытки их изменения обычно нормально компилируются. Данный совет лишь напоминает вам о том, что при модификации элементов
set/multiset
не следует изменять ключевую часть (то есть ту часть элемента, которая влияет на порядок сортировки в контейнере). В противном случае целостность данных контейнера будет нарушена, операции с контейнером начнут приводить к непредсказуемым результатам, и все это произойдет по вашей вине. С другой стороны, это ограничение относится только к ключевым атрибутам объектов, содержащихся в контейнере. Остальные атрибуты объектов находятся в вашем полном распоряжении — изменяйте на здоровье!

Впрочем, не все так просто. Хотя элементы

set/multiset
и не являются неизменными, реализации могут предотвратить их возможную модификацию. Например, оператор
*
для
set<T>::iterator
может возвращать
const T&
, то есть результат разыменования итератора
set
может быть ссылкой на
const
элемент контейнера! При такой реализации изменение элементов
set
и
multiset
невозможно, поскольку при любом обращении к элементу автоматически добавляется объявление
const
.

Законны ли такие реализации? Может, да, а может — нет. По этому вопросу Стандарт высказывается недостаточно четко, и в соответствии с законом Мерфи разные авторы интерпретируют его по-разному. В результате достаточно часто встречаются реализации STL, в которых следующий фрагмент компилироваться не будет (хотя ранее говорилось о том, что он успешно компилируется):

EmplIDSet se; // Контейнер set объектов

// Employee, упорядоченных

// по коду

Employee selectedID; // Объект работника с заданным кодом

EmpIDSet::iterator = se.find(selectedID);

if (i!=se.end) {

 i->setTitle("Corporate Deity"); // Некоторые реализации STL

}; // выдают ошибку в этой строке

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

set
и
multiset
, не переносимы.

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

Газлайтер. Том 23

Володин Григорий Григорьевич
23. История Телепата
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Газлайтер. Том 23

Древесный маг Орловского княжества 3

Павлов Игорь Васильевич
3. Орловское княжество
Фантастика:
аниме
сказочная фантастика
фэнтези
попаданцы
гаремник
5.00
рейтинг книги
Древесный маг Орловского княжества 3

Заповедник гоблинов (сборник)

Саймак Клиффорд Дональд
Фантастика:
научная фантастика
5.00
рейтинг книги
Заповедник гоблинов (сборник)

Законы рода

Мельник Андрей
1. Граф Берестьев
Фантастика:
фэнтези
боевая фантастика
аниме
5.00
рейтинг книги
Законы рода

Лимитерия

Хог Лимит
Проза:
современная проза
7.50
рейтинг книги
Лимитерия

Вампир. Английская готика. XIX век

Стивенсон Роберт Льюис
Фантастика:
ужасы и мистика
7.67
рейтинг книги
Вампир. Английская готика. XIX век

Адептка второго плана

Мамаева Надежда Николаевна
Попасть в историю
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Адептка второго плана

Долг

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

Ваше Сиятельство 5

Моури Эрли
5. Ваше Сиятельство
Фантастика:
городское фэнтези
аниме
5.00
рейтинг книги
Ваше Сиятельство 5

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

Винокуров Юрий
26. Кодекс Охотника
Фантастика:
попаданцы
5.00
рейтинг книги
Кодекс Охотника. Книга XXVI

Слезы Эйдена 1

Владимиров Денис
11. Глэрд
Фантастика:
боевая фантастика
фэнтези
попаданцы
5.00
рейтинг книги
Слезы Эйдена 1

Перешагнуть пропасть

Муравьёв Константин Николаевич
1. Перешагнуть пропасть
Фантастика:
боевая фантастика
космическая фантастика
8.38
рейтинг книги
Перешагнуть пропасть

Газлайтер. Том 4

Володин Григорий Григорьевич
4. История Телепата
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Газлайтер. Том 4

Глава рода

Шелег Дмитрий Витальевич
5. Живой лёд
Фантастика:
боевая фантастика
6.55
рейтинг книги
Глава рода