// конструирует итератор end_of_stream, который будет служить маркером
// конца потока в итераторной паре
istream_iterator string end_of_stream
vectorstring text;
// правильно: передаем пару итераторов
copy( is_string, end_of_stream,
inserter( text, text.begin() ));
Начальную позицию дает istream_iterator, инициализированный объектом istream, – такой, скажем, как is_string. Для получения конечной позиции мы используем специальный конструктор по умолчанию класса istream_iterator.
12.4.5. Итератор ostream_iterator
Объявление потокового итератора записи ostream_iterator может быть представлено в двух формах:
Если бы компилятор полностью удовлетворял стандарту C++, достаточно было бы написать так:
istream_iterator input_set1( infile1 ), eos;
istream_iterator input_set2( infile2 );
ostream_iterator identifier( ostream& )
ostream_iterator identifier( ostream&, char * delimiter )
где Type – это любой встроенный или пользовательский тип класса, для которого определен оператор вывода (operator). Во второй форме delimiter – это разделитель, то есть C-строка символов, которая выводится в файл после каждого элемента. Такая строка должна заканчиваться двоичным нулем, иначе поведение программы не определено (скорее всего, она аварийно завершит выполнение). В качестве аргумента ostream может выступать объект класса ostream, например cout, либо
#include iterator
#include fstream
#include string
#include complex
// записать последовательность объектов типа complex
// в стандартный вывод, разделяя элементы пробелами
ostream_iterator complex os_complex( cin, " " );
// записать последовательность строк в именованный файл
ofstream outfile( "dictionary" );
производного от него класса с открытым типом наследования, скажем ofstream:
ostream_iterator string os_string( outfile, "\n" );
Вот простой пример чтения из стандартного ввода и копирования на стандартный вывод с помощью безымянных потоковых итераторов и обобщенного алгоритма copy():
#include iterator
#include algorithm
#include iostream
int main()
{
copy( istream_iterator int ( cin ),
istream_iterator int (),
ostream_iterator int ( cout, " " ));}
Ниже приведена небольшая программа, которая открывает указанный пользователем файл и копирует его на стандартный вывод, применяя для этого алгоритм copy() и потоковый итератор записи ostream_iterator:
#include string
#include algorithm
#include fstream
#include iterator
main()
{
string file_name;
cout "please enter a file to open: ";
cin file_name;
if ( file_name.empty() || !cin ) {
cerr "unable to read file name\n"; return -1;
}
ifstream infile( file_name.c_str());
if ( !infile ) {
cerr"unable to open " file_name endl;
return -2;
}
istream_iterator string ins( infile ), eos;
ostream_iterator string outs( cout, " " );
copy( ins, eos, outs );
}
12.4.6. Пять категорий итераторов
Для поддержки полного набора обобщенных алгоритмов стандартная библиотека определяет пять категорий итераторов, положив в основу классификации множество операций. Это итераторы чтения (InputIterator), записи (OutputIterator), однонаправленные (ForwardIterator) и двунаправленные итераторы (BidirectionalIterator), а также итераторы с произвольным доступом (RandomAccessIterators). Ниже приводится краткое обсуждение характеристик каждой категории:
* итератор чтения можно использовать для получения элементов из контейнера, но поддержка записи в контейнер не гарантируется. Такой итератор должен обеспечивать следующие операции (итераторы, поддерживающие также дополнительные операции, можно употреблять в качестве итераторов чтения при условии, что они удовлетворяют минимальным требованиям): сравнение двух итераторов на равенство и неравенство, префиксная и постфиксная форма инкремента итератора для адресации следующего элемента (оператор ++), чтение элемента с помощью оператора разыменования (*). Такого уровня поддержки требуют, в частности, алгоритмы find(), accumulate() и equal(). Любому алгоритму, которому необходим итератор чтения, можно передавать также и итераторы категорий, описанных в пунктах 3, 4 и 5;
* итератор записи можно представлять себе как противоположный по функциональности итератору чтения. Иными словами, его можно использовать для записи элементов контейнера, но поддержка чтения из контейнера не гарантируется. Такие итераторы обычно применяются в качестве третьего аргумента алгоритма (например, copy()) и указывают на позицию, с которой надо начинать копировать. Любому алгоритму, которому необходим итератор записи, можно передавать также и итераторы других категорий, перечисленных в пунктах 3, 4 и 5;