
- •4.6. Иерархия итераторов stl: эффективная комбинация алгоритмов и контейнеров
- •4.7. Итераторы вставки
- •4.8. Еще раз о входе и выходе: потоковые итераторы
- •4.9. Спецификация категорий итераторов, требуемых алгоритмами stl
- •4.10. Разработка обобщенных алгоритмов
- •4.11. Почему некоторые алгоритмы требуют более мощные итераторы
- •4.12. Выбор правильного алгоритма
- •4.13. Константные и изменяемые итераторы
- •4.14. Категории итераторов, предоставляемые контейнерами stl
4.14. Категории итераторов, предоставляемые контейнерами stl
В табл. 4.1 показаны категории каждого типа итераторов, которые предоставляют контейнеры STL. Обратите внимание, что для set и multiset как iterator, так и const_iterator представляют собой константные двунаправленные итераторы — т.е. фактически это один и тот же тип. Причина этого в том, что единственный разрешенный метод изменения ключа— это его удаление (при помощи функции-члена erase), а затем вставка другого ключа (посредством функции-члена insert). Если бы итераторы множеств и мультимножеств были
неконстантными, то было бы можно модифицировать ключи без участия функций-членов erase и insert, и такое изменение могло бы привести к нарушению свойства размещения элементов в отсортированном порядке. Приведенный ниже пример иллюстрирует сказанное:
#include <set>
set<int> s;
s.insert(3);
s.insert(5);
s.insert(7);
set<int> :: iterator i = s.begin();
*i = 4; // Неверно
Эта программа не будет компилироваться, поскольку i представляет собой константный итератор, а элементы не могут быть изменены посредством константного итератора. Вместо этого мы должны записать
s.erase(i);
s.insert(4);
Аналогичное ограничение действует и для отображений и мультиотображений. Объект типа map<Кеу, Т> хранит значения типа pair<const Key, T>. Ключ данной пары не может быть модифицирован непосредственно, но можно модифицировать значение типа Т. Эта идея иллюстрируется приведенным ниже примером:
#include <map>
typedef multimap<int, double> multimap_1;
multimap_1 m;
m.insert(pair<const int, double>(3, 4.1));
multimap_1::iterator i = m.begin();
*i = pair<const int, double>(3, 5.1); // Неверно
Это неверный метод изменения значений, и компилироваться такой код не будет.
Корректный метод состоит в удалении значения, на которое указывает i, и вставке новой пары:
m.erase(i);
m.insert(pair<const int, double>(3, 5.1));
Можно также записать
i->second = 5.1;
поскольку значения, связанные с ключами, могут быть изменены с помощью неконстантного итератора. Такой метод предпочтительнее, поскольку он эффективнее, чем erase и insert. Однако он не будет работать, если объявить i как multimap_1: :const_iterator, поскольку константные итераторы не допускают изменения значений, на которые они указывают.
Таблица 4.1. Категории итераторов, предоставляемые контейнерами STL
Контейнер |
Итератор |
Категория итератора |
Т а[п] |
T* |
Изменяемый с произвольным доступом |
Т а[п] |
const T* |
Константный с произвольным доступом |
vector<T> |
vector<T>::iterator |
Изменяемый с произвольным доступом |
vector<T> |
vector<T>::const_iterator |
Константный с произвольным доступом |
deque<T> |
deque<T>::iterator |
Изменяемый с произвольным доступом |
deque<T> |
deque<T>::const_iterator |
Константный с произвольным доступом |
list<T> |
list<T>::iterator |
Изменяемый двунаправленный |
list<T> |
list<T>::const_iterator |
Константный двунаправленный |
set<T> |
set<T>::iterator |
Изменяемый двунаправленный |
set<T> |
set<T>::const_iterator |
Константный двунаправленный |
multiset<T> |
multiset<T>::iterator |
Изменяемый двунаправленный |
multiset<T> |
multiset<T>::const_iterator |
Константный двунаправленный |
map<Key,T> |
map<Key,T>::iterator |
Изменяемый двунаправленный |
map<Key,T> |
map<Key,T>::const_iterator |
Константный двунаправленный |
multimap<Key,T> |
multimap<Key,T>::iterator |
Изменяемый двунаправленный |
multimap<Key,T> |
multimap<Key,T>::const_iterator |
Константный двунаправленный |