我最近阅读了一篇文章,其中指出使用\n
比使用std::endl
更可取,因为endl
也会刷新流。
但是当我找到关于这个主题的更多信息时,我找到了一个声明的网站:
如果您处于必须避免缓冲的情况,可以使用std :: endl而不是'\ n'
现在我的问题出现了:在哪种情况下,写入缓冲区更好不?因为我只看到了那种技术的优点。写缓冲区是否更安全?因为它比硬盘驱动器小,所以它会比存储在HD上的数据更快地被覆盖(我不确定这是否属实)。
答案 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;
}
输出:
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;
}
输出:
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::cout
和std::cin
时,系统会自动完成此操作,除非您对同步设置进行了混乱。
许多程序员似乎使用std::endl
作为拼写'\n'
的奇特方式,但事实并非如此。每次向其写入内容时,您都不需要刷新输出缓冲区。让操作系统和标准库完成他们的工作;他们会及时将输出到达适当的地方。只需要一个简单的std::cout << '\n';
即可将换行符放入输出中,迟早会出现在显示屏上。如果您需要立即显示,通常是因为您暂时编写了所有输出并且不想让显示的信息不完整,请在最后一行之后使用std::endl
输出。