Шрифт:
Интервал:
Закладка:
В стандартной библиотеке есть тип ostream_iterator, предназначенный для работы с потоком вывода; ostream_iterator<T> — это итератор, который можно использовать для записи значений типа T.
В стандартной библиотеке есть также тип istream_iterator<T> для чтения значений типа T.
istream_iterator<string> ii(cin); // чтение *ii — это чтение строки
// из cin
string s1 = *ii; // т.е. cin>>s1
++ii; // "готов к вводу следующего
// элемента"
string s2 = *ii; // т.е. cin>>s2
Используя итераторы ostream_iterator и istream_iterator, можно вводить и выводить данные с помощью алгоритма copy(). Например, словарь, сделанный наспех, можно сформировать следующим образом:
int main()
{
string from, to;
cin >> from >> to; // вводим имена исходного
// и целевого файлов
ifstream is(from.c_str()); // открываем поток ввода
ofstream os(to.c_str()); // открываем поток вывода
istream_iterator<string> ii(is); // создаем итератор ввода
// из потока
istream_iterator<string> eos; // сигнальная метка ввода
ostream_iterator<string> oo(os,"n"); // создаем итератор
// вывода в поток
vector<string> b(ii,eos); // b — вектор, который
// инициализируется
// данными из потока ввода
sort(b.begin(),b.end()); // сортировка буфера
copy(b.begin(),b.end(),oo); // буфер копирования для вывода
}
Итератор eos — это сигнальная метка, означающая “конец ввода.” Когда поток istream достигает конца ввода (который часто называется eof), его итератор istream_iterator становится равным итератору istream_iterator, который задается по умолчанию и называется eos.

vector<string> b(max_size); // не пытайтесь угадать объем входных
// данных
copy(ii,eos,b.begin());
Люди, пытающиеся угадать максимальный размер ввода, обычно недооценивают его, переполняют буфер и создают серьезные проблемы как для себя, так и для пользователей. Переполнение буфера может также создать опасность для сохранности данных.
ПОПРОБУЙТЕ
Приведите программу в рабочее состояние и протестируйте ее на небольшом файле, скажем, содержащем несколько сотен слов. Затем испытайте “настоятельно не рекомендованную версию”, в которой объем входных данных угадывается, и посмотрите, что произойдет при переполнении буфера ввода b. Обратите внимание на то, что наихудшим сценарием является тот, в котором вы не замечаете ничего плохого и передаете программу пользователям.
В нашей маленькой программе мы считываем слова, а затем упорядочиваем их. Пока все, что мы делаем, кажется очевидным, но почему мы записываем слова в “неправильные” ячейки, так что потом вынуждены их сортировать? Кроме того, что еще хуже, оказывается, что мы записываем слова и выводим их на печать столько раз, сколько они появляются в потоке ввода.
Последнюю проблему можно решить, используя алгоритм unique_copy() вместо алгоритма copy(). Функция unique_copy() просто не копирует повторяющиеся идентичные значения. Например, при вызове обычной функции copy() программы введет строку
the man bit the dog
и выведет на экран слова
bit
dog
man
the
the
Если же используем алгоритм unique_copy(), то программа выведет следующие слова:
bit
dog
man
the

ostream_iterator<string> oo(os,"n"); // создает итератор для
// потока вывода
Очевидно, что переход на новую строку — это распространенный выбор для вывода, позволяющий людям легче разбираться в результатах, но, возможно, вы предпочли бы использовать пробелы? Мы могли бы написать следующий код:
ostream_iterator<string> oo(os," "); // создает итератор для потока
// вывода
В этом случае результаты вывода выглядели бы так:
bit dog man the
21.7.3. Использование класса set для поддержания порядка
Существует еще более простой способ получить такой вывод: использовать контейнер set, а не vector.
int main()
{
string from, to;
cin >> from >> to; // имена исходного и целевого файлов
ifstream is(from.c_str()); // создаем поток ввода
ofstream os(to.c_str()); // создаем поток вывода
istream_iterator<string> ii(is); // создаем итератор ввода
// из потока
istream_iterator<string> eos; // сигнальная метка для ввода
ostream_iterator<string> oo(os," "); // создаем итератор
// вывода в поток
set<string> b(ii,eos); // b — вектор, который инициализируется
// данными из потока ввода
copy(b.begin(),b.end(),oo); // копируем буфер в поток вывода
}

21.7.4. Алгоритм copy_if()
Алгоритм copy() выполняет копирование без каких-либо условий. Алгоритм unique_copy() отбрасывает повторяющиеся соседние элементы, имеющие одинаковые значения. Третий алгоритм копирует только элементы, для которых заданный предикат является истинным.
template<class In,class Out,class Pred>
Out copy_if(In first,In last,Out res,Pred p)
// копирует элементы, удовлетворяющие предикату
{
while (first!=last) {
if (p(*first)) *res++ = *first;
++first;
}
return res;
}
Используя наш объект-функцию Larger_than из раздела 21.4, можем найти все элементы последовательности, которые больше шести.
void f(const vector<int>& v)
// копируем все элементы, которые больше шести
{
vector<int> v2(v.size());
copy_if(v.begin(),v.end(),v2.begin(),Larger_than(6));
// ...
}
