Вход/Регистрация
Эффективное использование STL
вернуться

Мейерс Скотт

Шрифт:

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

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
, не переносимы.

  • Читать дальше
  • 1
  • ...
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

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