
- •4.6. Иерархия итераторов stl: эффективная комбинация алгоритмов и контейнеров
- •4.7. Итераторы вставки
- •4.8. Еще раз о входе и выходе: потоковые итераторы
- •4.9. Спецификация категорий итераторов, требуемых алгоритмами stl
- •4.10. Разработка обобщенных алгоритмов
- •4.11. Почему некоторые алгоритмы требуют более мощные итераторы
- •4.12. Выбор правильного алгоритма
- •4.13. Константные и изменяемые итераторы
- •4.14. Категории итераторов, предоставляемые контейнерами stl
4.8. Еще раз о входе и выходе: потоковые итераторы
Сейчас мы немного детальнее рассмотрим категории входных и выходных итераторов. Важной причиной включения этих категорий в STL является возможность указания алгоритмов, которые могут использоваться с итераторами, связанными с потоками ввода-вывода. Такие итераторы предоставляются классами STL istream_iterator (для ввода) и ostream_iterator (для вывода). Итераторы, создаваемые istream_iterator, являются входными, но не выходными
итераторами. Это означает, что объекты istream_iterator могут читать данные только в одном направлении и что запись данных при помощи этого объекта итератора невозможна.
Конструктор istream_iterator (istream&) типа istream_iterator<T> создает
входной итератор для значений типа Т из данного входного потока (такого, как стандартный поток ввода с in в приведенном далее примере).
Конструктор istream_iterator<T> () генерирует входной итератор, который
работает в качестве маркера конца для итераторов istream. Это просто значение, которому итераторы istream становятся равны, когда связанный с ними входной поток сообщает о достижении конца потока.
С итераторами istream могут использоваться такие алгоритмы, как merge, поскольку им требуется единственный проход по данным, и только их чтение, но не запись. Вот пример такого использования:
vector<int> vector1;
list<int> list1;
// ... Код вставки значений в vector1
merge(vector1.begin(), vector1.end(),
istream_iterator<int>(cin),
istream_iterator<int>(),
back_inserter(list1));
Здесь выполняется слияние целых чисел из vector1 с числами из стандартного потока ввода cin и размещение получающейся последовательности в list1 при помощи итератора вставки, построенного с помощью вызова back_inserter.
Итераторы istream из предыдущего примера могут быть использованы и в качестве первой пары итераторов алгоритма merge:
merge(istream_iterator<int>(cin), istream_iterator<int>(),
vector1.begin(), vector1.end(),
back_inserter(list1));
но мы не можем использовать итератор istream в качестве последнего аргумента, поскольку merge требуется возможность записи новых значений посредством этого итератора, что, конечно же, невозможно сделать посредством итератора istream_iterator.
Итераторы, созданные с применением вызова ostream_iterator, представляют собой выходные итераторы, не являющиеся входными. Такой алгоритм, как merge, может использовать такие итераторы, но только в качестве последнего аргумента:
vector<int> vector1;
list<int> listl;
// ... Код для вставки значений в vector1
// ... Код для вставки значений в list1
merge(vector1.begin(), vector1.end(),
list1.begin(), list1.end(),
ostream_iterator<int>(cout, " "));
В этом примере выполняется слияние целых чисел из вектора vector1 с целыми
числами из списка list1, и передача получившейся в результате последовательности в стандартный поток вывода cout, со вставкой пробелов между значениями при выводе (для этого служит второй аргумент конструктора ostream_iterator).
Итератор ostream нельзя использовать в качестве ни одного из первых четырех аргументов merge, так как алгоритму merge требуется возможность читать данные посредством разыменования этих итераторов, a ostream_iterator такой функциональности не предоставляет.