На этом шаге мы рассмотрим организацию работы с потоковыми буферами.
Все функции классов basic_istream и basic_ostream, выполняющие чтение или запись символов, работают по одной схеме: сначала конструируется соответствующий объект sentry, а затем выполняется операция. Конструирование объекта sentry приводит к очистке буферов возможных связанных объектов, игнорированию пропусков (только при вводе) и выполнению операций, специфических для конкретных реализаций, например операций блокировки файлов в средах с параллельным функционированием нескольких потоков выполнения (threads), то есть в многопоточных средах (смотри 508 шаг).
При неформатированном вводе-выводе многие операции потоков данных все равно бесполезны, разве что операция блокировки может пригодиться при работе с потоками в средах с параллельным функционированием нескольких потоков выполнения (поскольку в 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();
Со следующего шага мы начнем рассматривать вопросы интернационализации.