На этом шаге мы рассмотрим использование функции advance().
Стандартная библиотека C++ содержит три вспомогательные функции для работы с итераторами: advance(), distance() и iter_swap(). Первые две функции предоставляют для любого итератора возможности, которыми обычно обладают только итераторы произвольного доступа: перемещение итератора сразу на несколько элементов вперед (или назад) и вычисление разности между итераторами. Третья вспомогательная функция меняет местами элементы, на которые ссылаются два итератора.
Функция advance() перемещает итератор, передаваемый ей в качестве аргумента. При этом смещение может производиться в прямом (или обратном) направлении сразу на несколько элементов:
#include <iterator> void advance (InputIterator& pos, Dist n)
Перемещает итератор ввода pos на n элементов вперед (или назад). Для двунаправленных итераторов и итераторов произвольного доступа значение n может быть отрицательным (перемещение в обратном направлении).
Dist - тип шаблона. Обычно является целым типом, поскольку для него вызываются такие операции, как <, ++, -- и сравнение с 0.
Обратите внимание, что функция advance() не проверяет выход за пределы end() (и не может проверять, поскольку в общем случае итератор не располагает информацией о контейнере, с которым он работает). Таким образом, вызов этой функции может привести к непредсказуемым последствиям из-за вызова оператора ++ в конце последовательности.
Благодаря разным трактовкам итераторов функция всегда использует оптимальную реализацию в зависимости от категории итератора. Для итераторов произвольного доступа она просто вызывает pos+=n. Следовательно, для таких итераторов функция advance() имеет постоянную сложность. Для остальных итераторов используется n-кратный вызов pos (или --pos, если значение n отрицательно). Таким образом, для всех остальных категорий итераторов функция advance() выполняется с линейной сложностью.
Чтобы иметь возможность свободно менять типы контейнера и итератора, используйте функцию advance() вместо оператора +=. Однако следует помнить, что при этом возможно непредвиденное снижение быстродействия при переходе на другие типы контейнеров, не поддерживающие итераторы произвольного доступа (именно из-за снижения быстродействия оператор += применяется только для итераторов произвольного доступа). Также помните, что функция advance() не возвращает значения, а оператор += возвращает новую позицию и может входить в более сложное выражение. Пример использования функции advance():
//--------------------------------------------------------------------------- #include <vcl.h> #include <iostream> #include <iterator> #include <list> #include <algorithm> #include <conio.h> //необходимо для getch() #pragma hdrstop //--------------------------------------------------------------------------- #pragma argsused using namespace std; std::string ToRus(const std::string &in) { char *buff = new char [in.length()+1]; CharToOem(in.c_str(),buff); std::string out(buff); delete [] buff; return out; } int main(int argc, char* argv[]) { list<int> coll; // Вставка элементов от 1 до 9 for (int i=1; i<=9; ++i) { coll.push_back(i); } list<int>::iterator pos = coll.begin(); // Вывод текущего элемента cout << ToRus("Текущий элемент: "); cout << *pos << endl; // Перемещение вперед на три элемента advance (pos, 3); // Вывод текущего элемента cout << ToRus("Текущий элемент: "); cout << *pos << endl; // Перемещение назад на один элемент advance (pos, -1); // Вывод текущего элемента cout << ToRus("Текущий элемент: "); cout << *pos << endl; getch(); return 0; } //---------------------------------------------------------------------------
Вызовы advance() переводят итератор на три элемента вперед и на один элемент назад. Результат:
Рис.1. Результат работы приложения
Существуют и другие применения функции advance(). Например, вы можете проигнорировать часть ввода от итераторов, читающих данные из входного потока.
На следующем шаге мы рассмотрим функцию distance().