На этом шаге мы рассмотрим основные категории итераторов.
Возможности итераторов не исчерпываются базовыми операциями. Конкретный состав операций, поддерживаемых итератором, зависит от внутренней структуры типа контейнера. Как обычно, STL поддерживает только те операции, которые выполняются с хорошим быстродействием. Например, если контейнер обеспечивает произвольный доступ, как векторы или деки, его итератор также сможет выполнять операции произвольного доступа, например, его можно установить сразу на пятый элемент.
Итераторы делятся на несколько категорий в зависимости от их общих возможностей. Итераторы стандартных контейнерных классов относятся к одной из двух категорий.
Чтобы программный код как можно меньше зависел от типа контейнера, постарайтесь по возможности избегать специальных операций с итераторами произвольного доступа. Например, следующий цикл работает с любым контейнером:
for (pos = coll .begin(); pos != coll.end(); ++pos) {
. . .
}
А этот цикл работает не со всеми контейнерами:
for (pos = coll .begin(); pos < coll.end(); ++pos) {
. . .
}
Единственное различие - наличие оператора < вместо != в условии второго цикла. Оператор < поддерживается только итераторами произвольного доступа, поэтому второй цикл не будет работать со списками, множествами и отображениями. В унифицированном коде, ориентированном на работу с любыми контейнерами, следует использовать оператор != вместо <. С другой стороны, это несколько снижает надежность кода, поскольку pos может случайно перейти в позицию за end(). Сами решайте, какая версия больше подходит для вашего случая. Выбор зависит от контекста, а иногда даже от личных предпочтений.
Чтобы избежать недопонимания, поясняем, что здесь речь идет о категориях, а не о классах итераторов. Категория определяет только возможности итераторов независимо от их типов. Согласно общей концепции STL, то есть на уровне чистой абстракции, любой объект, который ведет себя как двунаправленный итератор, является двунаправленным итератором.
На следующем шаге мы рассмотрим алгоритмы.