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

Сначала выясним, почему элементы set и multiset не имеют атрибута const. Допустим, у нас имеется класс Emplоуее:

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 с объектами Emplоуее было бы вполне разумно упорядочить его по кодам работников:

struct IDNumberLess:

public binary_function { // См. совет 40

bool operator() (const Employees Ihs,

const Employees rhs) const

{

return lhs.idNumber() < rhs. IdNumber();

}

}

typedef set EmplIDSet;

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

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

// по коду

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

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

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

if (i!=se.end()){

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

}

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

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

Откровенно говоря, мне это кажется вполне логичным, однако мое личное мнение в данном случае несущественно. Важно то, что Комитет по стандартизации решил, что ключи map/multimap должны быть неизменными (const), а значения set/ multiset — не должны.

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

Перейти на страницу:

Все книги серии Библиотека программиста

Похожие книги