C++ - Почему fflush(stdout) не работает с iostream?

Я читал о freopen() и понял, что если мы укажем для него stdin/stdout, функция будет работать, даже если мы будем кодировать, используя cin/cout.

Немного изучив, я нашел эту ссылку freopen(), эквивалентную потокам С++, где один из пользователей ответил:

Из стандарта C++ 27.3.1:
«Объект cin управляет вводом из буфера потока, связанного с объектом stdin, объявленным в <cstdio>».

Таким образом, согласно стандарту, если мы перенаправляем stdin, он также перенаправить cin. Наоборот для cout.

Также видел нечто подобное на CPPReference:
http://en.cppreference.com/w/cpp/io/cin
http://en.cppreference.com/w/cpp/io/cout

Глобальные объекты std::cout и std::wcout управляют выводом в буфер потока типа, определяемого реализацией (производного от std::streambuf), связанного со стандартным потоком вывода C stdout.

Вот тут-то и возникло некоторое замешательство, так как я также читал о флешах и заметил, что fflush(stdout) просто не будет работать с cin/cout.

Например, этот пример кода ничего не напечатает:

#include <cstdio>
#include <iostream>

using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n;
    cout << "Please, enter a number: \n";
    fflush(stdout);
    cin >> n;
}

Пока этот код ниже будет печатать в output.txt:

#include <cstdio>
#include <iostream>

using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);

    freopen("output.txt", "w", stdout);

    cout << "Some string";
    while (true);
}

Удалив ios::sync_with_stdio(false); из первого примера кода, он ведет себя так, как ожидалось. И freopen() работает в любом случае (с ним или без него).

Итак, вопрос: почему fflush(stdout) не работает с iostream, а freopen(..., stdout) работает? Может быть, этот вопрос может стать еще глубже: какое расширение cin/cout связано с stdin/stdout?

Простите за длинный пост. Я старался быть максимально подробным и кратким.

Надеюсь понятно.

Заранее спасибо.

P.S.: ios::sync_with_stdio(false); и cin.tie(0); поставил специально.


person Enzo Nakamura    schedule 21.01.2017    source источник
comment
У меня нет немедленного ответа относительно работы freopen и fflush, за исключением того, что это зависит от реализации, и нет стандарта, гарантирующего, что cstdio работает вместе с iostream, поэтому кажется пустой тратой времени даже пытаться. Если вам нужно перенаправление, используйте stackoverflow.com/questions/10150468/   -  person stijn    schedule 21.01.2017
comment
Какой компилятор/библиотека конкретно будет печатать в output.txt? Я не наблюдаю этого ни с gcc/libstdc++, ни с clang/libc++ в моем Linux: файл остается пустым, пока цикл вращается.   -  person Cubbi    schedule 21.01.2017


Ответы (2)


Мой первый вопрос: «А зачем вам это?» Для этой цели существует функция std::ostream::flush(), поэтому используйте ее, например. cout.flush();.

Причина, по которой это "не работает", заключается в том, что буфер, который сбрасывается с помощью fflush(FILE* f), не является тем же самым буфером, который используется для std::ostream (или, по крайней мере, не гарантируется, что он будет). Вполне вероятно, что std::ostream::flush() действительно вызывает fflush(FILE*) для базового файлового объекта, который является частью реализации.

person Mats Petersson    schedule 21.01.2017

Назначение вызовов ios::sync_with_stdio(false) и cin.tie(0), которые вы поместили «намеренно», состоит в том, чтобы гарантировать (1) что потоки CI/O (stdout и т. д.) не синхронизированы с их аналогами C++ (std::cout и т. д.) и (2) чтобы убедитесь, что stdout и stdin не связаны (т. е. чтение из stdin не обязательно приводит к очистке stdout).

Вот почему fflush(stdout) не влияет на std::cout в вашем примере. Вы специально отключили такой эффект, и они могут буферизоваться отдельно.

Влияние freopen() на любой поток C++, который может быть синхронизирован с предоставленным дескриптором файла, не определено. На практике могут использоваться некоторые общие буферы, что объясняет то, что вы видите, по крайней мере, с вашим компилятором/библиотекой. Но такое поведение не гарантируется с другими реализациями.

person Peter    schedule 21.01.2017