Шаг 216.
Библиотека STL. Итераторы STL. Вспомогательные функции итераторов. Перебор итераторов функцией advance()

    На этом шаге мы рассмотрим использование функции advance().

    Стандартная библиотека C++ содержит три вспомогательные функции для работы с итераторами: advance(), distance() и iter_swap(). Первые две функции предоставляют для любого итератора возможности, которыми обычно обладают только итераторы произвольного доступа: перемещение итератора сразу на несколько элементов вперед (или назад) и вычисление разности между итераторами. Третья вспомогательная функция меняет местами элементы, на которые ссылаются два итератора.

Перебор итераторов функцией advance()

    Функция 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().




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