Шаг 176.
Библиотека STL. Контейнеры STL. Операции над отображениями и мультиотображениями. Функции получения итераторов

    На этом шаге мы рассмотрим функции получения итераторов.

    Отображения и мультиотображения не поддерживают прямой доступ к элементам, поэтому для обращения к элементам обычно используются итераторы.

    Впрочем, у этого правила существует исключение: отображения поддерживают оператор индексирования [] для прямого обращения к элементам. В таблице 1 перечислены стандартные функции получения итераторов, поддерживаемые отображениями и мультиотображениями.

Таблица 1. Операции получения итераторов для отображений и мультиотображений
Операция Описание
c.begin() Возвращает двунаправленный итератор для первого элемента (ключи считаются константными)
c.end() Возвращает двунаправленный итератор для позиции за последним элементом (ключи считаются константными)
c.rbegin() Возвращает обратный итератор для первого элемента при переборе в обратном направлении
c.rend() Возвращает обратный итератор для позиции за последним элементом при переборе в обратном направлении

    Итераторы отображений и мультиотображений, как и во всех классах ассоциативных контейнеров, являются двунаправленными. Такие итераторы не могут использоваться алгоритмами, рассчитанными на итераторы произвольного доступа (например, алгоритмами сортировки или случайной перестановки элементов).

    Но еще более важное ограничение заключается в том, что с точки зрения итератора все ключи элементов отображения или мультиотображения считаются константными (то есть элемент интерпретируется как относящийся к типу pair<const key,T>). Это необходимо для того, чтобы программа не могла нарушить упорядоченность элементов, изменяя их ключи. Однако в результате для элементов отображения или мультиотображения вызов модифицирующих алгоритмов становится невозможным. Например, удаление элементов не может осуществляться алгоритмом remove(), потому что "удаление" в действительности сводится к перезаписи следующими элементами (данная тема подробно обсуждается на 108 шаге). Элементы множеств и мультимножеств удаляются только функциями, предоставляемыми контейнером.

    Пример использования итераторов:

  std::map<std::string,float> coll;
  std::map<std::string,float>::iterator pos; 
  for (pos = coll.begin(); pos != coll.end(); ++pos) {
    std::cout << "key: " << pos->first  << "\t"
    << "value: " << pos->second << std::endl; 
  }

    Итератор pos используется для перебора в последовательности пар string/float. Выражение pos->flrst определяет ключ элемента, а выражение pos->second - значение элемента.


   Замечание. pos->first является сокращенной записью для (*pos).first. Некоторые старые библиотеки поддерживают только полную форму записи.

    Попытка изменения ключа приводит к ошибке:

  pos->first = "hello";   // ОШИБКА компипяции

    Однако модификация значения элемента выполняется без проблем (при условии, что значение не принадлежит к константному типу):

  pos->second = 13.5;    // OK

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

namespace MyLib {
  template <class Cont>
  inline
  bool replace_key (Cont& c,
                    const typename Cont::key_type& old_key, 
                    const typename Cont::key_type& new_key)
  {
    typename Cont::iterator pos; 
    pos = c.find(old_key); 
    if (pos != c.end()) {
      // Вставка нового элемента со значением старого элемента
      c.insert(typename Cont::value_type(new_key,pos->second));
      // Удаление старого элемента
      c.erase(pos);
      return true;
    } else 
    {
      // Ключ не найден
      return false;
    }
  }
}

    Функции insert() и erase() описаны в следующем шаге.

    При вызове этой унифицированной функции контейнеру просто передаются два ключа: старый и новый. Пример:

  std::map<std::string,float> coll;
  .   .   .   .   .
  MyLib::replace_key(coll,"old key","new key");

    С мультиотображениями функция работает аналогично. Впрочем, отображения поддерживают более удобный способ модификации ключа элемента. Вместо вызова replace_key() достаточно написать следующее:

  // Вставка нового элемента со значением старого элемента 
  coll["new_key"] = coll["old_key"];
  // Удаление старого элемента 
  coll.erase("old_key");

    На следующем шаге мы рассмотрим вставку и удаление элементов.




Предыдущий шаг Содержание Следующий шаг