2012-05-09 4 views
1

В случае буферизованного потока он сказал в книге, что он ждет, пока буфер не будет заполнен, чтобы записать обратно на монитор. Например:Буферизованный и небуферизованный поток

cout << "hi"; 
  1. Что они означают "буфер заполнен".

    cerr << "hi"; 
    
  2. Говорят, в своей книге, что все отправляется cerr записывается на стандартное устройство ошибки сразу же, что это значит?

    char *ch; 
    cin>> ch; // I typed "hello world"; 
    
  3. В этом примере ch будет назначен «привет» и «мир» будет игнорироваться это значит, что он все еще находится в буфере, и это будет влиять на результаты будущих заявлений?

+0

Стандартное примечание: по умолчанию 'cout' синхронизируется с' stdio', и по умолчанию ' stdio' - буферизируется по строке. – ybungalobill

+2

Собственно, во втором примере вы будете записывать в память в неизвестном месте и вызывать неопределенное поведение ... ** надеюсь, что ** приведет к сбою. –

ответ

9

Ваша книга не очень полезна.

1) Выходные потоки отправляют свои байты в std::streambuf, которые могут содержать буфер; std::filebuf (производный от streambuf), используемый и std::ofstream, как правило, буферизуется. Это означает, что когда вы выводите символ, он не обязательно выводится немедленно; он будет записываться в буфер и выводиться в ОС только тогда, когда буфер заполнен , или вы явно запросите его каким-то образом, как правило, путем вызова flush() в потоке (прямо или косвенно, используя std::endl). Это может меняться, однако; выход на std::cout синхронизируется с stdout, и большинство реализаций будет более или менее следовать правилам stdout для std::cout, изменения стратегии буферизации, если выход будет интерактивным устройством.

Во всяком случае, если вы не уверены, и вы хотите быть уверены, что выход действительно покинет вашу программу, просто добавьте вызов для очистки.

2) Ваша книга здесь не так.

Одна из стратегий буферизации - unitbuf; это флаг в std::ostream, который можно установить или сбросить (std::ios_base::set() и std::ios_base::unset()std::ios_base является базовым классом std::ostream, так что вы можете вызывать эти функции на std::ostream объекта). Когда unitbuf установлен, std::ostream добавляет вызов flush() к концу каждой выходной функции, поэтому, когда вы пишете:

std::cerr << "hello, world"; 

поток будет очищен после всех из символов в строке выводятся , при условии, что установлено unitbuf. При запуске unitbuf установлено для std::cerr; по умолчанию он не установлен ни в одном другом файле. Но вы, , можете установить или отключить его по своему усмотрению. Я бы порекомендовал против , установив его на std::cerr, но если std::cout выводит на интерактивное устройство , это имеет смысл установить его там.

Обратите внимание, что все, о чем идет речь, это буфер в streambuf. Как правило, ОС также буферизуется. Вся промывка буфера составляет , перевод символов в ОС; этот факт означает, что вы не можете использовать ofstream непосредственно, когда требуется целостность транзакции.

3) При вводе в строку или буфер символов с помощью >>, то std::istream первые скачет ведущие пробельные, а затем вводит до , но не включая следующее белое пространство. В формальных терминах стандарта он «извлекает» символы из потока, так что они больше не будут видны (если вы не ищете, если поток поддерживает его). Следующий вход будет срабатывать, когда бы ни было остановлено предыдущее. Будут ли следующие символы в буфере или все еще на диске, действительно неуместны.

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

Таким же образом, как std::ostream использует streambuf для вывода, std::istream использует один, чтобы получить каждый индивидуальный характер. В случае от std::cin он обычно будет filebuf; когда istream запрашивает символ, filebuf вернет его из своего буфера, если имеет один; если это не так, он попытается пополнить буфер, с запросом, например. 512 (или независимо от его размера буфера) от ОС. Который ответит в соответствии со своей политикой буферизации для устройства , как описано выше.

Во всяком случае, если std::cin подключен к клавиатуре, и вы набрали "hello world", все символы, которые вы уже напечатанных будет читаться потоком в конце концов. (Но если вы используете >>, там будет много неиспользованного что вы не увидите.)

2

потоки в C++ - это буфер для повышения эффективности, то есть файл и консоль ввода-вывода очень медленны по сравнению с операциями с памятью.

Для борьбы с этим потоком C++ есть буфер (банк памяти), содержащий все, чтобы записать в файл или выводить, когда он заполнен, затем он покраснел в файл. Инверсия верна для ввода, она извлекает больше, когда буфер исчерпан.

Это очень импорта для потоков, так как следующий

std::cout << 1 << "hello" << ' ' << "world\n"; 

Будет 4 записывает в файл, который является неэффективным.

Однако в случае std :: cout, cin и cerr эти типы фактически имеют буферизацию, отключенную по умолчанию, чтобы гарантировать ее использование в сочетании с std :: printf и std :: puts и т. Д. .

Чтобы повторно включить его (который я рекомендую делать):

std::ios_base::sync_with_stdio(false); 

Но не следует использовать консольный вывод в стиле C, пока он установлен ложные или плохое может случиться.

+0

, поэтому в вашем примере «1hello world \ n» будет сначала передаваться в буфер, а затем на экран. но если я сделал cerr << 1 << "hello" << "<< << world \ n"; то 1 будет передан на экран, а затем «привет» и так далее ... это правильно? спасибо – AlexDan

+0

@AlexDan хорошо «1hello world \ n» будет записан в буфер, он будет записан на экран, когда любой пользователь хочет от пользователя, операции извлечения cin синхронизируют два потока, вызывающих сброс cout. Когда вы вручную очищаете поток, используя std :: cout << std :: flush или std :: cout << std :: endl; Или когда поток разрушен и закрыт (конец программы IE для std :: cout или конец области для файлов). – 111111

+0

@AlexDan Cerr и Cout отличаются файловым дескриптором, который они тоже отправляют, cout переходит на stdout и cerr переходит в stderror. когда вы устанавливаете их не для синхронизации с stdio, тогда они оба буферизуют, когда это правда, то оба они небуферированы. Это говорит о том, что 'clog' такой же, как' cerr', но я считаю, что он всегда буферизирован. – 111111

0
  1. Каждый вызов записи на терминал медленно, так, чтобы не делать медленные вещи часто данные не хранятся в памяти, пока либо определенный объем данных был введен или буфер очищается вручную с fflush или станд :: епсИ. В результате этого иногда бывает, что текст не может быть записан на терминал в тот момент, когда вы его ожидаете.

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

  3. Этот мир по-прежнему находится в буфере, но это очень легко доказать это, попробовав его в 3-строчной программе. Однако ваш пример не удастся, так как вы пытаетесь записать в нераспределенную память. Вместо этого вы должны вводить ввод в std :: string.

+0

Точка 2 на самом деле не верна. 'Filebuf'' std :: cerr' по-прежнему буферизует, как обычно. Разница в том, что 'unitbuf' установлен, что означает, что' ostream' делает флеш в конце каждого '>>'. (Фактически, в деструкторе сторожевого объекта, построенного в верхней части функции.) –

+0

@JamesKanze - это единственные вещи, которые делают сброс буфера: fflush ot std :: endl; ? как насчет cout << "hello"; cout << «мир»; – AlexDan

+0

@AlexDan No. Если не установлен 'unitbuf', в этом случае в конце каждого« << »появится флеш. –

1

1), что делают они означают "буфер заполнен".

С буферизированным выходом имеется область памяти, называемая буфером, где материал, который вы выписываете, сохраняется до того, как он будет фактически записан на выход. Когда вы говорите cout << "hi", строка, вероятно, только копируется в этот буфер и не выписывается. cout обычно ждет, пока эта память не будет заполнена до того, как она начнет писать вещи.

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

2) В моей книге сказано, что все, отправленное в cerr, немедленно записывается на стандартное устройство ошибок, означает ли это, что он отправляет «h», а затем «i» ...?

Это просто означает, что буфер не используется. cerr может по-прежнему отправлять «h» и «i» одновременно, так как у них уже есть оба.

3) в этом примере ch будет присвоен «привет», а «мир» будет проигнорирован, означает ли это, что он все еще находится в буфере, и это повлияет на результаты будущих утверждений?

Это не имеет никакого отношения к буферизации. оператор >> для char * определяется как прочитанный, пока не увидит пробелы, поэтому он останавливается в промежутке между «привет» и «миром». Но да, в следующий раз, когда вы прочтете, вы получите «мир».

(хотя, если этот код не просто пересказ actuall кода, то это неопределенное поведение, потому что вы читаете текст в неопределенную ячейку памяти Вместо этого вы должны сделать:.

std::string s; 
cin >> s; 

)

2

Вы можете проверить отличия самостоятельно с помощью небольшого приложения.

#include <iostream> 
int main() { 
    std::cout<<"Start"; 
    //std::cout<<"Start"<<std::endl; // line buffered, endl will flush. 
    double j = 2; 
    for(int i = 0; i < 100000000; i++){ 
     j = i/(i+1); 
    } 
    std::cout<<j; 
    return 0; 
} 

Попробуйте разницу двух статусов «Старт», затем измените на cerr. Разница, которую вы заметили, связана с буферизацией.

Заявление занимает около 2 секунд на моей установке, вам может потребоваться настроить i < на ваше.

+0

Извините, но я получаю тот же результат. Начните, а затем через 1 секунду я получу 0 – AlexDan

+0

Если вы получите этот результат из того, как он написан здесь, у вас есть небуферизованный std :: cout. –

+0

Или очень медленная консоль. Например, на окнах :) – sehe

Смежные вопросы