Программирование >>  Операторы преобразования типа 

1 ... 209 210 211 [ 212 ] 213 214 215 ... 239


#include inbufl.hpp

int mainO {

inbuf ib: Создание специального потокового буфера

std::istream in(&ib); Инициализация выходного потока этим буфером

char с:

for (int i-1: 1<-20; i++) {

Чтение следующего символа (из буфера) in.get(c):

Вывод символа и очистка буфера std::cout с std::flush:

После вывода восьми символов

вернуть два последних символа в поток

if (i == 8) {

in.ungetO:

in.ungetO;

std::cout Std::endl:

Программа в циЕсле читает символы и выводит их в поток данных cout. После чтения восьмого символа выполняется возврат на два символа, в результате чего седьмой и восьмой символы выводятся дважды.

Проблемы эффективности

Данный раздел посвящен вопросам эффективности. Вообще говоря, потоковые классы обычно работают достаточно эффективно, но в приложениях, критичных по быстродействию ввода-вывода, их можно сделать еще эффективнее.

Одна из проблем быстродействия уже упоминалась на с. 567: в программу должны включаться только заголовочные файлы, абсолютно необходимые для компиляции. В частности, следует избегать включения файла <iostream>, если в профамме не используются стандартные потоковые объекты.

Синхронизация со стандартными потоками данных С

По умолчанию восемь стандартных потоков данных С++ (четыре символьных потока с однобайтовой кодировкой dn, cout, сегг и ciog, а также четыре их аналога с расширенной кодировкой) синхронизируются с соответствующими каналами из стандартной библиотеки С (stdin, stdout и stderr). По умолчанию ciog и wciog



используют тот же потоковый буфер, что и cerr и wcerr соответственно. Таким образом, по умолчанию они синхронизируются с stderr, хотя в стандартной библиотеке С у этих потоков данных нет прямых аналогов.

В зависимости от реализации синхронизация может приводить к лишним затратам. Например, если стандартные потоки данных С++ реализованы с использованием стандартных файлов С, это фактически подавляет буферизацию соответствующих потоковых буферов. Однако буферизация необходима для выполнения некоторых оптимизаций, особенно для форматированного чтения (см. далее). Чтобы программист мог переключиться на нужную реализацию, в классе ios base определена статическая функция sync with stdio() (табл. 13.46).

Таблица 13.46. Синхронизация стандартных потоков данных С++ и С

Статическая Описание

функция

syncwtth stdio() Возвращает информацию о том, синхронизируются ли стандартные

объекты потоков данных со стандартными потоками данных С

sync with stdio(false) Запрещает синхронизацию потоков данных С++ и С (при условии,

что функция была вызвана до первой операции ввода-вывода)

При вызове функции sync with stdio() передается необязательный логический аргумент, который указывает, нужно ли активизировать синхронизацию со стандартными потоками данных С. Для отключения синхронизации функция вызывается с аргументом feise:

std::1os::sync wlth std1o(false); Отключение синхронизации

Помните, что синхронизация отключается только до выполнения любой операции ввода-вывода. Если зто условие не выполнено, последствия от вызова функции зависят от реализации.

Функция sync with stdio() возвращает значение, использованное при предыдущем вызове. Если ранее функция не вызывалась, она всегда возвращает true, отражающее состояние по умолчанию для стандартных потоков данных.

Буферизация в потоковых буферах

Буферизация ввода-вывода также является важным фактором эффективности. Системные вызовы обычно обходятся относительно дорого, поэтому их количество должно быть по возможности сведено к минимуму. Тем не менее существует и другая, более тонкая причина для буферизации в потоковых буферах С++ (по крайней мере, при вводе): функции форматного ввода-вывода работают с потоками данных при помощи итераторов потоковых буферов, а операции с итераторами медленнее операций с указателями. Отличия не так уж велики, но вполне достаточны для того, чтобы оправдать применение оптимизированных реализаций для частых операций (например, форматированного ввода числовых данных). Однако для этого необходимо атрименение буферизации в потоковых буферах.



Итак, весь ввод-вывод осуществляется через потоковые буферы, обеспечивающие механизм буферизации. Но полагаться только на эту буферизацию недостаточно по трем причинам.

О Потоки данных без буферизации часто реализуются проще. Если соответствующие потоки данных используются редко или только для вывода (для вывода различия между итераторами и указателями не столь существенны, как для ввода; основная проблема - сравнение итераторов потоковых буферов), вероятно, буферизация не играет особой роли. Но если потоковый буфер интенсивно используется, для него определенно следует реализовать буферизацию.

О При установленном флаге unitbuf выходной поток данных очищает буфер после каждой операции вывода. Кроме того, очистка производится манипуляторами flush и endi. Вероятно, для оптимального быстродействия следует избегать всех трех способов. Но при выводе на консоль, например, было бы логично очищать буфер после вывода полных строк. Если вы зашли в тупик с программой, интенсивно использующей манипуляторы unitbuf, flush и endi, рассмотрите возможность применения специального потокового буфера, который в соответствующий момент вызывает не функцию sync(), а другую функцию.

О Связывание потоков данных функцией tie() (см. с. 612) также требует дополнительных операций очистки потоков данных. Следовательно, связывание должно применяться только при абсолютной необходимости.

При разработке новых потоковых буферов рекомендуется сначала реализовать их без буферизации. Если потоковый буфер окажется узким местом - в работе системы, вы сможете организовать буферизацию так, чтобы не затронуть другие компоненты приложения.

Непосредственная работа с потоковыми буферами

Все функции классов basicjstream и basic ostream, выполняющие чтение или запись символов, работают по одной схеме: сначала конструируется соответствующий объект sentry, а затем выполняется операция. Конструирование объекта sentry приводит к очистке буферов возможных связанных объектов, игнорированию пропусков (только при вводе) и выполнению операций, специфических для конкретных реализаций, например операций блокировки файлов в средах с параллельным функционированием нескольких потоков вьшолнения (threads), то есть в многопоточных средах (см. с. 631).

При неформатированном вводе-выводе многие операции потоков данных все равно бесполезны, разве что операция блокировки может пригодиться при работе с потоками в средах с параллельным функционированием нескольких по-ToicoB выполнения (поскольку в С++ проблемы многопоточности не решаются). Следовательно, при неформатированном вводе-выводе прямая работа с потоковыми буферами обычно более эффективна.



1 ... 209 210 211 [ 212 ] 213 214 215 ... 239

© 2006 - 2025 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки.
Яндекс.Метрика