Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
STL5 / lab4-iterators / lab4-iterators.doc
Скачиваний:
13
Добавлен:
10.04.2015
Размер:
299.01 Кб
Скачать

Итераторы потоков ввода-вывода

Библиотека STLпозволяет обращаться с потоками файлового и консольного ввода-вывода (а также с любыми другими классами, производными отistream иostream) как с контейнерами: для них существуют специальные итераторыistream_iterator иostream_iterator. Рассмотрим пример: Нижеприведенная программа вводит с клавиатуры целые числа - коды символов - и печатает символы, соответствующие этим кодам.

istream_iterator<char> input(cin); // (1)

istream_iterator<char> inputEnd; // (2)

ostream_iterator<string> output(cout); // (3)

while(input!=inputEnd) { // (4)

*output=string("Symbol: " + (*input) +"\n"); // (5)

++input; // (6)

++output; // (7)

}

(1): Создаем итератор входного потока input, итерирующий поток консольного вводаcin. Этот итератор будет перебирать символы.

(2): Конструктор итератора входного потока без аргументов создает итератор, означающий конец входного потока (законечный). Все такие итераторы считаются равными друг другу, независимо от того, принадлежат они какому-либо потоку или нет.

(3): Создаем итератор выходного потока output, итерирующий поток консольного выводаcout. Он будет перебирать строки.

(4): Равенство итератора входного потока законечному итератору означает конец данных во входном потоке.

Обратим внимание, что итератор inputEnd создавался без аргументов, т.е. он не относится к какому-либо конкретному потоку, тогда как итераторinputотносится к потокуcin. Тем не менее, библиотекаSTLустроена так, что когда будет достигнут конец входного потока, итераторinputстанет равным этому итератору (хоть и не будет его копией): оператор == устроен так, что считает равными все законенчые итераторы входных потоков.

(5): *inputвозвращает очередной элемент из входного потока, присваивание*outputзаписывает элемент в выходной поток.

(6), (7): Передвигаем итераторы на следующий элемент в каждом из потоков..

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

Итераторы вставки (insert iterators).

Вывод данных через итератор, приводит к перезаписи элементов контейнера. Если места в контейнере не достаточно, может произойти выход за пределы допустимого диапазона.

Пример кода:

list<int> l1, l2;

//... Заполнить списки

copy(l1.begin(), l1.end(), l2.begin());

сopy() – один из стандартных алгоритмов, копирующий элементы одной последовательности, заданной парой итераторов (первый и второй параметры), поверх элементов второй последовательности, для которой задан итератор начала (третий параметр), количество копируемых элементов определяется первой последовательностью. Так если размер спискаl2 был меньше спискаl1, то произойдет выход итератора из допустимого диапазона, что приведет к неопределенному поведению.

STLсодержит итераторы вставки, которые позволяют не перезаписывать элементы контейнера, а вставлять их в начало (front_insert_iterator), конец (back_insert_iterator) или произвольную позицию (insert_iterator). Определения этих итераторов находятся в заголовочном файле <iterator>. В дополнениеSTLсодержит три вспомогательные функции, которые могут быть использованы для создания этих итераторов:back_inserter() для созданияback_insert_iterator,front_inserter() для созданияfront_insert_iteratorиinserter() для созданияinsert_iterator. Явно создавать итераторы вставки необходимости нет.

// Создать итератор вставки в начало контейнера с

template<class Cont>

back_insert_iterator<Cont> back_inserter(Cont&c);

// Создать итератор вставки в конец контейнера с

template<class Cont>

front_insert_iterator<Cont> front_inserter(Cont&c);

// Создать итератор вставки, который будет осуществлять вставку перед позицией указываемой итератором p в контейнер с

template<class Cont, class Out>

insert_iterator<Cont> front_inserter(Cont&c, Out p);

Эти функции могут быть использованы следующим образом:

list<int> l1, l2;

//... Заполнить списки

// Добавить содержимое l1 в начало l2

copy(l1.begin(), l1.end(), front_inserter(l2));

// Добавить содержимое l1 в конец l2

copy(l1.begin(), l1.end(), back_inserter(l2));

// Добавить содержимое l1 в l2, начиная вставку со второй позиции

copy(l1.begin(), l1.end(), inserter(l2,l2.begin()++));

Рассмотрим реализацию итератора вставки в конец, она достаточно просто и при этом интересна:

template <class Container>

class back_insert_iterator : public output_iterator

{

protected:

Container& container;

public:

back_insert_iterator(Container& x) : container(x) {}

back_insert_iterator <Container>&

operator=(const Container::value_type& value)

{

container.push_back(value);

return *this;

}

back_insert_iterator<Container>& operator*() { return *this; }

back_insert_iterator<Container>& operator++() { return *this; }

back_insert_iterator<Container>& operator++(int) { return *this; }

};

template <class Container>

back_insert_iterator<Container> back_inserter(Container& x) {

return back_insert_iterator<Container>(x);

}

На первый взгляд кажется странным наличие оператора присваивания итератору некоторого значению типа указываемого объекта, и уж совсем странно выглядят операторы * и ++. Однако посмотрим, что происходит на самом деле.

Пусть имеется объект X типа back_insert_iterator. Напишем *X=a; При этом operator*() возвратит сам объект X и для него вызовется operator=(const Container::value_type& value), который и вставит этот элемент в конец контейнера.

Странная семантика операторов ++ объясняется тем, что они вовсе не должны вызываться. Это – итератор вывода и 2 последовательных увеличения итератора без записи недопустимы. Однако продвижение итератора вызывается в операции присваивания, таким образом лимит продвижений исчерпан, больше ниоткуда вызывать продвижение нельзя.

Похожим образом реализованы классы front_insert_iterator (производящая функция front_inserter) и insert_iterator (inserter).

Соседние файлы в папке lab4-iterators