Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
КРАТКИЙ ОБЗОР С.doc
Скачиваний:
1
Добавлен:
26.10.2018
Размер:
2.11 Mб
Скачать

10.5.1 Закрытие потоков

Файл может быть закрыт явно, если вызвать close() для его потока:       mystream.close(); Но это неявно делает деструктор потока, так что явный вызов close() может понадобиться, если только файл нужно закрыть до достижения конца области определенности потока.       Здесь возникает вопрос, как реализация может обеспечить создание предопределенных потоков cout, cin и cerr до их первого использования и закрытие их только после последнего использования. Конечно, разные реализации библиотеки потоков из <iostream.h> могут по-разному решать эту задачу. В конце концов, решение - это прерогатива реализации, и оно должно быть скрыто от пользователя. Здесь приводится только один способ, примененный только в одной реализации, но он достаточно общий, чтобы гарантировать правильный порядок создания и уничтожения глобальных объектов различных типов.       Основная идея в том, чтобы определить вспомогательный класс, который по сути служит счетчиком, следящим за тем, сколько раз <iostream.h> был включен в раздельно компилировавшиеся программные файлы:       class Io_init {       static int count;       //...       public:       Io_init();       ^Io_init();       };       static Io_init io_init ; Для каждого программного файла определен свой объект с именем io_init. Конструктор для объектов io_init использует Io_init::count как первый признак того, что действительная инициализация глобальных объектов потоковой библиотеки ввода-вывода сделана в точности один раз:       Io_init::Io_init()       {       if (count++ == 0) {       // инициализировать cout       // инициализировать cerr       // инициализировать cin       // и т.д.       }       } Обратно, деструктор для объектов io_init использует Io_count, как последнее указание на то, что все потоки закрыты:       Io_init::^Io_init()       {       if (--count == 0) {       // очистить cout (сброс, и т.д.)       // очистить cerr (сброс, и т.д.)       // очистить cin       // и т.д.       }       } Это общий прием работы с библиотеками, требующими инициализации и удаления глобальных объектов. Впервые в С++ его применил Д. Шварц. В системах, где при выполнении все программы размещаются в основной памяти, для этого приема нет помех. Если это не так, то накладные расходы, связанные с вызовом в память каждого программного файла для выполнения функций инициализации, будут заметны. Как всегда, лучше, по возможности, избегать глобальных объектов. Для классов, в которых каждая операция значительна по объему выполняемой работы, чтобы гарантировать инициализацию, было бы разумно проверять такие первые признаки (наподобие Io_init::count) при каждой операции. Однако, для потоков такой подход был бы излишне расточительным.

10.5.2 Строковые потоки

Как было показано, поток может быть привязан к файлу, т.е. массиву символов, хранящемуся не в основной памяти, а, например, на диске. Точно так же поток можно привязать к массиву символов в основной памяти. Например, можно воспользоваться выходным строковым потоком ostrstream для форматирования сообщений, не подлежащих немедленной печати:       char* p = new char[message_size];       ostrstream ost(p,message_size);       do_something(arguments,ost);       display(p); С помощью стандартных операций вывода функция do_something может писать в поток ost, передавать ost подчиняющимся ей функциям и т.п. Контроль переполнения не нужен, поскольку ost знает свой размер и при заполнении перейдет в состояние, определяемое fail(). Затем функция display может послать сообщение в "настоящий" выходной поток. Такой прием наиболее подходит в тех случаях, когда окончательная операция вывода предназначена для записи на более сложное устройство, чем традиционное, ориентированное на последовательность строк, выводное устройство. Например, текст из ost может быть помещен в фиксированную область на экране.       Аналогично, istrstream является вводным строковым потоком, читающим из последовательности символов, заканчивающейся нулем:       void word_per_line(char v[], int sz)       /*       печатать "v" размером "sz" по одному слову в строке       */       {       istrstream ist(v,sz); // создать istream для v       char b2[MAX]; // длиннее самого длинного слова       while (ist>>b2) cout <<b2 << "\n";       } Завершающий нуль считается концом файла.       Строковые потоки описаны в файле <strstream.h>.