На этом шаге мы рассмотрим организацию работы с потоковыми буферами.
Все функции классов basic_istream и basic_ostream, выполняющие чтение или запись символов, работают по одной схеме: сначала
конструируется соответствующий объект sentry, а затем выполняется операция. Конструирование объекта sentry приводит к очистке
буферов возможных связанных объектов, игнорированию пропусков (только при вводе) и выполнению операций, специфических для конкретных
реализаций, например операций блокировки файлов в средах с параллельным функционированием нескольких потоков выполнения (threads),
то есть в многопоточных средах (смотри 508 шаг).
При неформатированном вводе-выводе многие операции потоков данных все равно бесполезны, разве что операция блокировки может пригодиться
при работе с потоками в средах с параллельным функционированием нескольких потоков выполнения (поскольку в C++ проблемы многопоточности
не решаются). Следовательно, при неформатированном вводе-выводе прямая работа с потоковыми буферами обычно более эффективна.
Для этого можно определить для потоковых буферов операторы << и >>.
- При получении указателя на потоковый буфер оператор << выводит все накопленные данные. Вероятно, это самый быстрый способ копирования
файлов с использованием потоков данных C++. Пример:#include <iostream> int main () { // Копирование стандартного ввода в стандартный вывод std::cout << std::cin.rdbuf(); }
В этом фрагменте функция rdbuf() возвращает буфер cin (смотри 508 шаг). Следовательно, программа
копирует весь стандартный входной поток данных в стандартный выходной поток. - При получении указателя на потоковый буфер оператор >> выполняет прямое чтение данных. Например, копирование стандартного входного
потока данных в стандартный выходной поток также может выполняться следующим образом:#include <iostream> int main () { // Копирование стандартного ввода в стандартный вывод s td::cin >> std::noskipws >> std::cout.rdbuf(); }
Обратите внимание на сброс флага skipws. В противном случае будут проигнорированы начальные пропуски во входных данных
(смотри 491 шаг).
Впрочем, прямая работа с потоковым буфером может быть оправдана даже при форматированном вводе-выводе. Например, если программа в цикле
вводит много числовых значений, может оказаться достаточным сконструировать всего один объект sentry, существующий на протяжении
всего цикла. Внутри цикла пропуски игнорируются вручную (использование манипулятора ws также привело бы к конструированию объекта
sentry), а прямое чтение числовых данных осуществляется фацетом num_get.
Учтите, что потоковый буфер не обладает собственным состоянием ошибки. Он также ничего не знает о входных или выходных потоках, которые
могут к нему подключиться. Следовательно, внутри следующего фрагмента состояние ошибки in не может измениться из-за сбоя или
достижения конца файла:// Копирование содержимого in в out out << in.rdbuf();
Со следующего шага мы начнем рассматривать вопросы интернационализации.