我最近阅读了一篇文章,其中指出使用比使用\n
更好,std::endl
因为它endl
也会刷新流.
但当我找到关于该主题的更多信息时,我发现了一个网站,其中说明:
如果您处于必须避免缓冲的情况,可以使用std :: endl而不是'\n'
现在我的问题出现了:在哪种情况下最好不要写入缓冲区?因为我只看到了那种技术的优点.写入缓冲区不是更安全吗?因为它比硬盘驱动器小,所以它会比存储在HD上的数据更快地被覆盖(我不确定这是否属实).
Mar*_* A. 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;
}
Run Code Online (Sandbox Code Playgroud)
输出:
bash: line 7: 22235 Segmentation fault (core dumped) ./a.out
Run Code Online (Sandbox Code Playgroud)
由于缓冲阻止了正确的输出显示,因此上面不会打印任何文本.
现在,如果你只是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;
}
Run Code Online (Sandbox Code Playgroud)
输出:
This text is quite nice and might as well be buffered
bash: line 7: 22444 Segmentation fault (core dumped) ./a.out
Run Code Online (Sandbox Code Playgroud)
这次输出在程序终止之前可见.
这一事实的含义是多方面的.纯粹推测:如果数据与服务器日志相关,那么您的应用程序可能在实际日志记录之前崩溃了.
Pet*_*etr 11
在任何你希望输出实际出现在应该出现的时候,它会更好.
一个简单的例子:
#include <iostream>
int main() {
std::cout << "Please enter your name: " << std::endl;
std::string name;
std::cin >> name;
...
}
Run Code Online (Sandbox Code Playgroud)
通过缓冲,在用户需要输入他/她的名字之前,屏幕上不会出现任何文本,因此用户会感到困惑.(请注意,事实上,在完全启用缓冲的情况下运行此示例可能非常困难或不可能,因为C++可能需要特殊措施std::cout
在输入之前进行刷新std::cin
,请参阅为什么我们需要绑定std :: cin和std ::清点?但是,这仅仅是一个理论上的例子:如果缓存中.完全启用,用户将不会看到提示)
这种情况可能会不时发生,尽管可能并非经常发生.考虑写入管道以与另一个进程交互.或者即使您的程序写入日志文件,您也会不时查看日志文件以查看它是如何运行的 - 如果是缓冲,您通常不会看到从程序打印的输出,但仍然留在缓冲区了.
要考虑的另一个重要情况 - 如果您的程序严重崩溃,缓冲区内容可能根本不会在硬盘驱动器上结束.(我希望流析构函数能够刷新缓冲区,但是崩溃可能非常严重,根本不会调用析构函数.)
小智 10
首先,有点修正主义的历史.
在过去,当每个人都使用stdio.h
库来进行I/O时,交互式查看的文本通常是行缓冲的(甚至是无缓冲的),而未完全缓冲的文本也是如此.因此,如果您输出'\n'
到流,它将"始终"执行正确的事情:用户正在查看的行被刷新并立即被看到,并且被转储到文件的行被缓冲以获得最大性能.
不幸的是,它实际上并不总是正确的事情; 运行时无法始终预测用户实际想要查看程序输出的方式.一个常见的陷阱是重定向STDOUT
- 人们习惯于在控制台中运行程序并在控制台中查看输出(带有行缓冲行为),然后出于任何原因(例如长时间运行的作业),他们决定重定向STDOUT
到文件,并立即惊讶于输出不再是行缓冲.
我已经看到因为这个原因浪费了数周的超级计算机时间; 输出很少,缓冲阻止任何人能够告诉工作进展情况.
iostream
然而,C++的库旨在让你在这里轻松做正确的事情.除了与stdio
它同步时,它不会做这个有趣的"可能行缓冲可能完全缓冲"的事情.它总是使用完全缓冲(当然,当你做无缓冲的东西时除外),如果你想在换行上刷新东西,你可以明确地这样做.
因此,如果您将一堆格式化文本转储到人们在完成之前不会查看的文件中,那么您可以\n
为换行符编写代码.
但是如果你正在写文字,人们可能真的想在你写作的时候看一下,你会用std::endl
你的换行符,它会立即显示出来.如果你一次写几行,你甚至可以做得更好:'\n'
用于中间换行符和std::endl
最后一行(或'\n'
和std::flush
).虽然在这个设置中性能通常无关紧要,但通常可以使用std::endl
所有的换行符.
我希望你丢失了你找到的那个网站的链接.std::endl
并没有避免缓冲.它刷新缓冲区中的任何内容.如果您需要避免缓冲,请使用setf(ios_base::unitbuf)
.这会在每次插入后将流设置为刷新.这是默认设置std::clog
.这样做的原因是缓冲区中保存的内容越少,关键数据在程序崩溃时写入流的可能性就越大.
刷新对于交互式程序也很重要:如果你写了一个提示std::cout
,如果在程序开始等待输入之前该提示出现在显示器上,这是一件好事.当您使用这就是自动完成std::cout
和std::cin
,除非你与同步设置弄乱.
许多程序员似乎都使用std::endl
拼写的方式'\n'
,但事实并非如此.每次向其写入内容时都不需要刷新输出缓冲区.让操作系统和标准库完成他们的工作; 他们会及时将产量输送到适当的地方.std::cout << '\n';
只需简单就可以将换行符放入输出中,迟早会出现在显示屏上.如果您现在需要显示它,通常是因为您暂时写了所有输出并且不想让显示的信息不完整,请std::endl
在输出的最后一行之后使用.