Шаг 231.
Библиотека STL.
Итераторы STL. Итераторные адаптеры. Потоковые итераторы ввода

    На этом шаге мы рассмотрим потоковые итераторы ввода.

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

    В момент создания потоковый итератор ввода инициализируется входным потоком данных, из которого будут читаться данные. Далее стандартный интерфейс итераторов ввода используется для чтения элементов оператором >>. Тем не менее чтение может завершиться неудачей (при достижении конца файла или возникновении ошибки), а интервальному источнику алгоритма необходима "конечная позиция". Обе проблемы решаются при помощи итератора конца потока данных, создаваемого конструктором но умолчанию потоковых итераторов ввода. Если попытка чтения завершается неудачей, все потоковые итераторы ввода превращаются в итераторы конца потока данных. Следовательно, после каждой операции чтения потоковый итератор ввода необходимо сравнивать с итератором конца потока данных и убеждаться в том, что он остался действительным. В таблице 1 перечислены псе операции потоковых итераторов ввода.

Таблица 1. Операции потоковых итераторов ввода
Выражение Описание
istream_iterator<T>() Создание итератора конца потока данных
istream_iterator<T> (istream) Создание потокового итератора ввода для потока данных istream (с чтением первого значения)
*iter Обращение к ранее прочитанному значению (читает первое значение, если оно не было прочитано конструктором)
iter1->member Обращение к переменной или функции ранее прочитанного значения
++iter Читает следующее значение и возвращает итератор для его позиции
iter++ Читает следующее значение, но возвращает итератор для предыдущего значения
iter1==iter2 Проверка iter1 и iter2 на равенство
iter1 != iter2 Проверка iter1 и iter2 на неравенство

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

    Потоковые итераторы вывода определяются для типа элемента Т:

namespace std {
  template <class T,
                 class char T = char, 
                 class traits = char_traits<char_T>, 
                 class Distance = ptrdiff_t > 
  class istream_iterator; 
}

    Необязательные второй и третий аргументы шаблона определяют тип используемого потока данных. Необязательный четвертый аргумент шаблона определяет тип разности итераторов.

    Два потоковых итератора ввода равны, если выполняется одно из следующих условий:

Следующий пример демонстрирует использование потокового итератора ввода.
//---------------------------------------------------------------------------

#include <vcl.h>
#include <iostream>
#include <iterator>
#include <vector>
#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[])
{
  // Создание потокового итератора ввода для чтения целых чисел из cin 
  istream_iterator<int> intReader(cin);

  // Создание итератора конца потока данных 
  istream_iterator<int> intReaderEOF;

  // Пока удается читать лексемы потоковым итератором ввода. 
  // - дважды вывести прочитанное значение 
  while (intReader != intReaderEOF) {
    cout << ToRus(" Читаем: " ) << *intReader << endl; 
    cout << ToRus("Еще раз: " ) << *intReader << endl; 
    ++intReader;
  }

  getch();
  return 0;
}

//---------------------------------------------------------------------------
Текст этого примера можно взять здесь.

    Пусть входными данными программы является следующая последовательность:

  1  2  3  f  4

    Если запустить программу с этими входными данными, результат ее выполнения будет выглядеть так:


Рис.1. Результат работы приложения

    Как видите, символ f во входном потоке данных завершает работу программы. Из-за ошибки формата дальнейшее чтение невозможно, поэтому потоковый итератор ввода intReader равен итератору конца потока данных intReaderEOF (а условие завершения цикла становится равным false).

    На следующем шаге мы рассмотрим еще один пример использования потоковых итераторов.




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