【问题标题】:When must the output stream in C++ be flushed?何时必须刷新 C++ 中的输出流?
【发布时间】:2014-01-28 07:12:33
【问题描述】:

我知道cout << '\n' 优于cout << endl;,但cout << '\n' 不会刷新输出流。什么时候应该刷新输出流,什么时候出现问题?

究竟什么是冲洗?

【问题讨论】:

  • stackoverflow.com/a/14107357/11862989 检查这个答案。我在此处引用特定部分何时应将字符写入外部目的地!这可能是在写入文件结束时(尽管关闭文件会隐式刷新缓冲区)或在要求用户输入之前(请注意,当从 std::cin 读取时,std::cout 会自动刷新,因为 std::cout 是 @987654328 @ 尽管在某些情况下您可能明确想要刷新流,但我发现它们相当罕见。

标签: c++ coding-style


【解决方案1】:

刷新强制输出流写入任何缓冲的字符。 Read streamed input/output.

这取决于您的应用程序,在实时或交互式应用程序中,您需要立即刷新它们,但在许多情况下,您可以等到关闭文件并让程序自动刷新它。

【讨论】:

    【解决方案2】:

    什么时候必须刷新 C++ 中的输出流?

    当您想确保写入它的数据对其他程序或(在文件流的情况下)对读取同一文件但与该文件无关的其他流可见时;以及当你想确定即使程序异常终止也能写入输出时。

    因此,在长时间计算之前打印消息或打印消息以指示出现问题时,您可能希望这样做(尽管您通常会为此使用 cerr,它会在每次输出后自动刷新) .

    通常不需要刷新cerr(默认情况下,它的unitbuf标志设置为在每次输出后刷新),或者在从cin读取之前刷新cout(这些流是绑定的cout 在读取 cin 之前会自动刷新)。

    如果您的程序的目的是产生大量的输出,无论是到cout 还是到一个文件,那么不要在每一行之后刷新 - 这可能会显着减慢它。

    究竟什么是冲洗?

    输出流包含内存缓冲区,写入速度通常比底层输出快得多。输出操作将数据放入缓冲区;冲洗将其发送到最终输出。

    【讨论】:

      【解决方案3】:

      首先,你读错了。无论您使用std::endl 还是'\n' 很大程度上取决于上下文,但如果有疑问,std::endl 是 正常的默认值。使用'\n' 保留用于以下情况 你事先知道冲洗是不必要的,而且它 成本太高。

      刷新与缓冲有关。当你写信给 一个流,(通常)数据不会立即写入 系统;它被简单地复制到一个缓冲区中,该缓冲区将被写入 当它已满或文件关闭时。或者当它是 显式刷新。这是出于性能原因:一个系统 call 通常是一个相当昂贵的操作,而且通常是 对每个角色都这样做不是一个好主意。从历史上看, C有一种叫做行缓冲模式的东西,它用 每个'\n',事实证明这是一个很好的妥协 对于大多数事情。由于各种技术原因,C++ 没有 有它;使用 std::endl 是 C++ 实现相同的方法 结果。

      我的建议是使用 std::endl 直到你 开始出现性能问题。如果没有别的,它使 调试更简单。如果你想走得更远,这是有意义的 当您输出一系列行时使用'\n' 几句话。还有一些特殊情况,比如日志记录, 您可能希望显式控制刷新。

      【讨论】:

      • 但即使我不使用std::endl,它仍然会在屏幕上打印输出。但是你说using std::endl is C++'s way of achieving the same results. 那么没有这个怎么会工作以及在这种情况下谁刷新缓冲区。
      【解决方案4】:

      如果您正在编写一个带有频繁空格的大文件,刷新可能是灾难性的。

      例如

      for(int i = 0 ;i < LARGENUMBER;i++)
      {//Slow?
        auto point = xyz[i];
        cout<< point.x <<",",point.y<<endl;
      }
      

      for(int i = 0 ;i < LARGENUMBER;i++)
      {//faster
        auto point = xyz[i];
        cout<< point.x <<",",point.y<<"\n";
      }
      

      for(int i = 0 ;i < LARGENUMBER;i++)
      {//fastest?
        auto point = xyz[i];
        printf("%i,%i\n",point.x,point.y);
      }
      

      endl() 通常以做其他事情而闻名,例如在 MSVC 上的所谓调试模式下同步线程,导致多线程程序出乎意料地从不同线程打印不间断的短语。

      【讨论】:

        【解决方案5】:

        出于性能原因,I/O 库会缓冲发送到流的数据。每当您需要确定数据实际上已发送到流时,您都需要刷新它(否则它可能仍在缓冲区中并且在屏幕或文件中不可见)。

        某些操作会自动刷新流,但您也可以显式调用诸如 ostream::flush 之类的操作。

        您需要确保数据已刷新,例如当您有其他程序等待第一个程序的输入时。

        【讨论】:

          【解决方案6】:

          这取决于你在做什么。例如,如果您正在使用控制台警告用户一个漫长的过程......在同一行打印一系列点......冲洗可能会很有趣。对于正常输出,每行一行,你不应该关心冲洗。

          因此,对于基于字符的输出或非基于行的控制台输出,可能需要刷新。对于基于行的输出,它按预期工作。

          这个其他答案可以澄清你的问题,基于为什么避免 endl 和手动刷新可能对性能有好处: mixing cout and printf for faster output

          关于什么是刷新:当您写入缓冲流(如 ostream)时,您无法保证数据到达目标设备(控制台、文件等)。发生这种情况是因为流可以使用中间缓冲区来保存您的数据并且不会停止您的程序。通常,如果您的缓冲区足够大,它们将保存所有数据并且不会由于 I/O 设备慢而停止您的程序。您可能已经注意到控制台非常慢。刷新操作告诉流您要确保所有中间数据都到达目标设备,或者至少它们的缓冲区现在是空的。这对于日志文件非常重要,例如,您希望确定(不是 100%)一行将在磁盘上而不是在某处的缓冲区中。如果您的程序不能丢失数据,这变得更加重要,即,如果它崩溃,您要确保您已尽力将数据写入磁盘。对于其他应用程序,性能更为重要,例如,您可以让操作系统决定何时为您刷新缓冲区或等到您关闭流。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2010-11-25
            • 1970-01-01
            • 2018-10-25
            • 2017-03-25
            • 1970-01-01
            • 2011-06-29
            相关资源
            最近更新 更多