在c ++中刷新流的后果和优缺点

时间:2015-04-17 13:56:53

标签: c++ theory flush

我最近阅读了一篇文章,其中指出使用\n比使用std::endl更可取,因为endl也会刷新流。
但是当我找到关于这个主题的更多信息时,我找到了一个声明的网站:

  

如果您处于必须避免缓冲的情况,可以使用std :: endl而不是'\ n'   

现在我的问题出现了:在哪种情况下,写入缓冲区更好?因为我只看到了那种技术的优点。写缓冲区是否更安全?因为它比硬盘驱动器小,所以它会比存储在HD上的数据更快地被覆盖(我不确定这是否属实)。

5 个答案:

答案 0 :(得分:19)

当发生缓冲时,您无法保证在刷新发生之前立即接收数据。在特定情况下,您可能会遇到错误的输出排序和/或信息/调试数据丢失,例如

int main() {

    std::cout << "This text is quite nice and might as well be buffered";
    raise(SIGSEGV); // Oh dear.. segmentation violation
    std::cout << std::endl;
}

Live Example

输出:

bash: line 7: 22235 Segmentation fault      (core dumped) ./a.out

以上将打印任何文本,因为缓冲阻止了正确的输出显示。

现在,如果你只是在缓冲区的末尾添加一个刷新std::endl,这就是你得到的

int main() {

    std::cout << "This text is quite nice and might as well be buffered" << std::endl;
    raise(SIGSEGV); // Oh dear.. segmentation violation
    std::cout << std::endl;
}

Live Example

输出:

This text is quite nice and might as well be buffered
bash: line 7: 22444 Segmentation fault      (core dumped) ./a.out

这次输出在程序终止之前可见

这一事实的含义是多方面的。纯粹是推测性的:如果数据与服务器日志相关,那么您的应用程序可能会在实际日志记录之前崩溃。

答案 1 :(得分:12)

在您希望输出实际显示在应该出现的任何情况下,这将是更好的。

一个简单的例子:

#include <iostream>
int main() {
    std::cout << "Please enter your name: " << std::endl;
    std::string name;
    std::cin >> name;
    ...
}

通过缓冲,在用户输入他/她的姓名之前,屏幕上不会显示任何文字,因此用户会感到困惑。 (请注意,事实上,在完全启用缓冲的情况下运行此示例可能非常困难或不可能,因为在std::cout的任何输入之前,C ++可能会采取特殊措施来刷新std::cin,请参阅{{3}但这只是一个理论上的例子:如果缓冲 完全启用,用户将看不到提示。)

这种情况可能会不时发生,尽管可能并非经常发生。考虑写入管道以与另一个进程交互。或者即使您的程序写入日志文件,您也会不时查看日志文件以查看它是如何运行的 - 如果是缓冲,您通常不会看到从程序打印的输出,但仍然留在缓冲区了。

要考虑的另一个重要情况 - 如果程序严重崩溃,缓冲区内容可能根本不会在硬盘驱动器上结束。 (我希望流析构函数能够刷新缓冲区,但崩溃可能非常严重,根本不会调用析构函数。)

答案 2 :(得分:10)

如果 需要 您的信息流的目标在流关闭之前接收数据,最好刷新缓冲区。

现实生活中的一个例子是应用程序日志,从始终打开的流中编写...您可能希望在程序运行时查看此日志。

答案 3 :(得分:10)

首先,有点修正主义的历史。

在过去,当每个人都使用stdio.h库来执行I / O时,以交互方式查看的文本通常是行缓冲(甚至无缓冲 ),以及不是完全缓冲的文本。因此,如果您将'\n'输出到流中,它将始终&#34;始终&#34;做正确的事情:用户看到的行会立即被刷新并被看到,并且被转储到文件的行被缓冲以获得最佳性能。

不幸的是,它实际上并不总是正确的事情;运行时无法始终预测用户实际想要查看程序输出的方式。一个常见的陷阱是重定向STDOUT - 人们习惯在控制台中运行程序并在控制台中查看输出(带有行缓冲行为),然后出于任何原因(例如长时间运行的作业)他们决定将STDOUT重定向到一个文件,并且对输出不再是行缓冲的事实感到惊讶。

我已经看到因为这个原因浪费了数周的超级计算机时间;输出很少,缓冲阻止任何人能够告诉工作进展情况。

然而,

C ++的iostream库旨在让 easy 在这里做正确的事。除了与stdio同步之外,它并没有做到这么有趣&#34;可能是行缓冲可能是完全缓冲的&#34;事情。 总是使用完全缓冲(当然,当你做无缓冲的东西时除外),如果你想在换行上刷新东西,你可以显式地

因此,如果您将一堆格式化文本转储到人们在完成之前不会查看的文件中,则为您的换行符写\n。< / p>

但是,如果您正在撰写文字时,人们可能实际上想要在您编写文字时查看文字,则可以使用std::endl作为换行符,并立即显示。如果你一次写几行,你甚至可以做得更好:使用'\n'表示中间换行符,std::endl表示最后一行(或'\n'和{{ 1}})。虽然在这种情况下,性能通常并不重要,但通常只需使用std::flush来表示所有换行符。

答案 4 :(得分:5)

我希望您已经丢失了您找到的该网站的链接。 std::endl 避免缓冲。它刷新缓冲区中的任何内容。如果您需要避免缓冲,请使用setf(ios_base::unitbuf)。这会在每次插入后将流设置为刷新。这是std::clog的默认设置。这样做的原因是缓冲区中保存的内容越少,程序崩溃时关键数据写入流的可能性就越大。

Flushing对于交互式程序也很重要:如果你向std::cout写了一个提示,如果在程序开始等待输入之前该提示出现在显示屏上,那就很好了。当您使用std::coutstd::cin时,系统会自动完成此操作,除非您对同步设置进行了混乱。

许多程序员似乎使用std::endl作为拼写'\n'的奇特方式,但事实并非如此。每次向其写入内容时,您都不需要刷新输出缓冲区。让操作系统和标准库完成他们的工作;他们会及时将输出到达适当的地方。只需要一个简单的std::cout << '\n';即可将换行符放入输出中,迟早会出现在显示屏上。如果您需要立即显示,通常是因为您暂时编写了所有输出并且不想让显示的信息不完整,请在最后一行之后使用std::endl输出。