C++ 刷新缓冲区

c++ flushing the buffer

本文关键字:缓冲区 刷新 C++      更新时间:2023-10-16

我知道这里有很多缓冲问题,但我似乎找不到明确的答案。

std::cout << "write to screen" << std::endl;

我知道这段代码会因为"endl"而写入屏幕并刷新缓冲区,但是如果我写了这个:

std::cout << "write to screen";

由于文本已输出到屏幕,因此不会刷新缓冲区吗?

由于文本已输出到屏幕,因此不会刷新缓冲区吗?

假设您已经看到输出到屏幕的文本,那么是的,缓冲区已被刷新。

我相信混乱是关于这一行的:

std::cout << "write to screen";

没有std::endl并不意味着"不要刷新缓冲区"。 它只是意味着"我不是说何时刷新缓冲区"。

有多种方法可以确保您的std::ostream被刷新:

  1. 手动使用 std::endlstd::flush 或直接调用 ostream::flush()
  2. 取决于以后使用的输入流绑定到您的 ostream:std::basic_ios::tie() .
  3. 取决于与 C 流的连接:std::ios_base::sync_with_stdio

    这意味着任何会刷新相应 C 流的东西也会刷新C++流,比如调用 fflush() 或(可能自动)选择的缓冲策略。
    比如行缓冲。

    从C11草案:

    7.21.3 文件

    3 当流未缓冲时,字符应从源或 尽快到达目的地。否则可能会累积字符和 作为块传输到主机环境或从主机环境传输。当流完全缓冲时, 字符旨在作为块传输到主机环境或从主机环境传输,在以下情况下 填充缓冲区。当流被行缓冲时,字符应 当换行符 遇到。此外,字符旨在作为块传输到主机 填充缓冲区时的环境,在未缓冲的流上请求输入时,或 当在需要传输 主机环境中的字符。对这些特征的支持是 实现定义,并可能通过 setbuf 和 setvbuf 函数受到影响。
    7 在程序启动时,预定义了三个文本流,不需要显式打开 — 标准输入(用于读取常规输入),标准输出(用于写入) 常规输出)和标准错误(用于写入诊断输出)。最初 打开时,标准错误流未完全缓冲;标准输入和标准 当且仅当可以确定流不引用时,输出流才会完全缓冲 到交互式设备。

  4. 等待内部缓冲区溢出。

现在,作为一般准则:不要手动刷新流,这样做会显著降低性能。当然,除非正确性是必要的。

std::cout << "Hello" << std::endl;

将在执行下一行代码之前写入屏幕,而

std::cout << "Hellon";

将打印相同的内容,但在您的程序正常退出或使用std::cin(或您手动绑定的另一个std::cout流)之前一段时间。这意味着,如果您的程序突然终止或在无限循环中挂起,您可能根本看不到输出。

"既然文本已输出到屏幕上,缓冲区不会刷新吗?"

不! std::endl意味着冲洗。基础缓冲区不会刷新(写入屏幕上), 直到达到某个水印(缓冲区大小)。

如果要刷新它,请明确调用cout.flush()

std::cout << "write to screen";
std::cout.flush();

解决方案的真正关键是底层std::basic_streambuf接口实际实现的内容。
可以有多种实现:

  1. 每次命中基础缓冲区的特定水位线时调用flush()
  2. 每次都调用flush()(效率不是很高)
  3. 打印'n'后立即呼叫flush()
  4. 通过std::endl保证呼叫flush()

内部缓冲区管理不应该是你关心的业务,除非你试图提供自己的std::basic_streambuf实现。