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

时间:2022-09-02 09:05:41

I have recently read an article which stated that using \n is preferable to using std::endl because endl also flushes the stream.
But when I looked for a bit more information on the topic I found a site which stated:

我最近读了一篇文章,上面说使用\n比使用std更可取::endl,因为endl也冲掉了流。但是当我寻找更多关于这个话题的信息时,我发现了一个网站:

If you are in a situation where you have to avoid buffering, you can use std::endl instead of ‘\n’

如果您需要避免缓冲,可以使用std::endl而不是' \n '

Now here comes my question: In which situation is it preferable not to write to the buffer? Because I only saw advantages of that technique. Isn't it also safer to write to the buffer? Because it is smaller than a hard drive it will get overwritten faster than data that is stored on the HD (I am not sure if this is true).

现在我的问题来了:在哪种情况下,不向缓冲区写代码更可取?因为我只看到了这种技术的优点。写到缓冲区不是更安全吗?因为它比硬盘还小,它会比HD上存储的数据写得更快(我不确定这是不是真的)。

5 个解决方案

#1


18  

When buffering occurs you will have no guarantees that the data is immediately received before a flush occurs. Under particular circumstances you might experience wrong output ordering and/or loss of information/debug data, e.g.

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

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

生活的例子

Output:

输出:

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

the above will not print any text since the buffering prevented the right output to be displayed.

由于缓存阻止了要显示的正确输出,上面的操作将不会打印任何文本。

Now if you simply add a flushing std::endl at the end of the buffer this is what you get

现在,如果您只是添加一个刷新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

生活的例子

Output:

输出:

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

This time the output is visible before the program termination.

这一次,输出在程序终止之前是可见的。

Implications of this fact are manifold. Purely speculative: if the data were related to a server log, your app could have been crashed before the actual logging.

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

#2


12  

It will be preferable in any situation in which you want the output to actually appear exactly when it was supposed to appear.

在任何您希望输出实际出现的情况下,它都是更可取的。

A simple example:

一个简单的例子:

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

With buffering, no text will appear on screen before the user is expected to type his/her name, so the user will be confused. (Note that in fact it might be really difficult or impossible to get this example run with buffering fully enabled, as C++ might take special measures to flush std::cout before any input from std::cin, see Why do we need to tie std::cin and std::cout?. But this is just a theoretical example: in case the buffering is fully enabled, the user will not see the prompt.)

在缓存中,在用户期望输入他/她的名字之前,屏幕上不会出现任何文本,因此用户将会感到困惑。(注意,在完全启用缓冲功能的情况下运行这个示例可能非常困难或不可能,因为在std::cin和std::cout输入之前,c++可能会采取特殊措施刷新std:::cout?但这只是一个理论示例:如果已完全启用缓冲,用户将看不到提示符。

Such a situation can occur from time to time, though it might not be very often. Consider writing to a pipe to interact with another process. Or even if your program writes to log file and you personally look into the log file from time to time to see how it runs --- in case of buffering, you usually will not see the output that has been printed from program, but still stays in the buffer yet.

这种情况有时会发生,虽然可能不是经常发生。考虑编写一个管道来与另一个进程交互。甚至如果程序写入日志文件和你个人的日志文件不时地看看它运行——在缓冲的情况下,你通常不会看到从程序的输出打印,但仍停留在缓冲。

Another important situation to account for --- if your program severely crashes, the buffer contents might not end on the hard drive at all. (I expect the stream destructors to flush the buffer, but a crash can be so severe that no destructors will be called at all.)

另一个需要考虑的重要情况是——如果您的程序严重崩溃,缓冲区内容可能根本不会在硬盘上结束。(我预计流析构函数会刷新缓冲区,但崩溃可能非常严重,根本不会调用任何析构函数。)

#3


10  

It is preferable to flush the buffer if you need the target of your stream to receive the data before the stream is closed.

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

A real-life example would be an application log, written from a stream that's always open... You may want to look at this log while the program is still running.

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

#4


10  

First, a bit of revisionist history.

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

In the old days, when everybody used stdio.h library to do I/O, text that was viewed interactively was typically line buffered (or even unbuffered), and text that was not was fully buffered. So, if you output '\n' to the stream, it would "always" do the Right Thing: lines users were looking at get flushed and seen immediately, and lines getting dumped to file get buffered for maximum performance.

在过去,每个人都使用stdio。h库用于执行I/O,交互查看的文本通常是行缓冲(甚至是未缓冲),而未完全缓冲的文本。因此,如果您将'\n'输出到流,那么它将“始终”做正确的事情:用户正在查看的行会立即被刷新并被看到,被转储到文件的行将被缓冲以获得最大的性能。

Unfortunately, it isn't actually always the Right Thing; the runtime cannot always predict how users actually want to view the output of your program. One common trap is redirecting STDOUT -- people get used to running their program in a console and seeing the output (with its line-buffered behavior) in the console, and then for whatever reason (e.g. long running job) they decide to redirect STDOUT to a file, and are promptly surprised by the fact the output is no longer line-buffered.

不幸的是,它并不总是正确的;运行时不能总是预测用户实际希望如何查看程序的输出。一个常见的陷阱是重定向标准输出——人们习惯于在控制台运行他们的程序和输出(其line-buffered行为)在控制台,然后不管出于什么原因(例如,长时间运行的工作)他们决定将标准输出重定向到一个文件,并立即惊讶的事实不再line-buffered的输出。

I have seen weeks of supercomputer time wasted for this reason; the output was infrequent enough that the buffering prevented anyone from being able to tell how the job was progressing.

由于这个原因,我看到了数周的超级计算机浪费时间;输出的频率非常低,以至于缓冲使任何人都无法知道作业是如何进行的。

C++'s iostream library, however, was designed to make it easy to do the Right Thing here. Except when synchronizing with stdio, it doesn't do this funny "maybe line-buffered maybe fully-buffered" thing. It always uses full buffering (except when you do unbuffered stuff, of course), and if you want things flushed on newline, you do so explicitly.

然而,c++的iostream库的设计目的是使在这里做正确的事情变得容易。除了与stdio同步时,它不会做这个有趣的“也许行缓冲也许完全缓冲”的事情。它总是使用完全缓冲(当然,当您做未缓冲的事情时除外),如果您想要在换行符上刷新内容,您可以显式地这么做。

So if you're dumping a bunch of formatted text to a file that people won't be looking at until it's done, you write \n for your line breaks.

如果你将一堆格式化的文本转储到一个文件中,直到它完成之后人们才会看到它,那么你就为换行符编写\n。

But if you're writing text people might actually want to look at while you're writing it, you use std::endl for your line breaks, and it gets displayed immediately. And if you're writing several lines at once, you can even do better: use '\n' for the intermediate line breaks and std::endl for the final one (or '\n' and std::flush). Although in this setting performance usually doesn't matter so it's usually fine to just use std::endl for all of the line breaks.

但是,如果你在写文本,人们可能会在你写的时候想要看一下,你可以使用std::endl作为换行符,它会立即显示出来。如果你同时写了几行,你甚至可以做得更好:使用'\n'作为中间换行符,使用std::endl作为最后一行(或者'\n'和std::flush)。尽管在这个设置中,性能通常并不重要,所以对于所有的断行,最好只使用std::endl。

#5


5  

I hope you've lost the link to that site that you found. std::endl does not avoid buffering. It flushes whatever is in the buffer. If you need to avoid buffering, use setf(ios_base::unitbuf). That sets the stream to flush after each insertion. That's the default setting for std::clog. The reason for doing this is that the less stuff being held in the buffer, the greater the chance that critical data will have been written to the stream when the program crashes.

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

Flushing also matters for interactive programs: if you write a prompt to std::cout, it's a Good Thing if that prompt shows up on the display before the program starts waiting for input. That's done automatically when you use std::cout and std::cin, unless you've messed with the synchronization settings.

刷新对于交互式程序也很重要:如果您向std::cout编写一个提示符,那么在程序开始等待输入之前,如果该提示符出现在显示中,这将是一件好事。当您使用std::cout和std::cin时,这是自动完成的,除非您打乱了同步设置。

Many programmers seem to use std::endl as a fancy way of spelling '\n', but it's not. You don't need to flush the output buffer every time you write something to it. Let the OS and the standard library do their jobs; they'll take care of getting the output to the appropriate place in a timely manner. A simple std::cout << '\n'; is all that's needed to put a newline into the output, and sooner or later, that will show up on the display. If you need to have it show now, typically because you've written all of the output for the time being and don't want to leave the displayed information incomplete, use std::endl after the last line of the output.

许多程序员似乎使用std::endl作为拼写“\n”的奇特方式,但它不是。您不需要每次向输出缓冲区写东西时都刷新它。让操作系统和标准库完成它们的工作;他们会及时把输出送到适当的地方。一个简单的std::cout < '\n';这就是在输出中加入换行符所需要的一切,并且迟早会在显示中显示出来。如果您需要现在显示它,通常是因为您已经编写了所有的输出,并且不希望显示的信息不完整,那么在输出的最后一行之后使用std::endl。

#1


18  

When buffering occurs you will have no guarantees that the data is immediately received before a flush occurs. Under particular circumstances you might experience wrong output ordering and/or loss of information/debug data, e.g.

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

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

生活的例子

Output:

输出:

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

the above will not print any text since the buffering prevented the right output to be displayed.

由于缓存阻止了要显示的正确输出,上面的操作将不会打印任何文本。

Now if you simply add a flushing std::endl at the end of the buffer this is what you get

现在,如果您只是添加一个刷新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

生活的例子

Output:

输出:

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

This time the output is visible before the program termination.

这一次,输出在程序终止之前是可见的。

Implications of this fact are manifold. Purely speculative: if the data were related to a server log, your app could have been crashed before the actual logging.

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

#2


12  

It will be preferable in any situation in which you want the output to actually appear exactly when it was supposed to appear.

在任何您希望输出实际出现的情况下,它都是更可取的。

A simple example:

一个简单的例子:

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

With buffering, no text will appear on screen before the user is expected to type his/her name, so the user will be confused. (Note that in fact it might be really difficult or impossible to get this example run with buffering fully enabled, as C++ might take special measures to flush std::cout before any input from std::cin, see Why do we need to tie std::cin and std::cout?. But this is just a theoretical example: in case the buffering is fully enabled, the user will not see the prompt.)

在缓存中,在用户期望输入他/她的名字之前,屏幕上不会出现任何文本,因此用户将会感到困惑。(注意,在完全启用缓冲功能的情况下运行这个示例可能非常困难或不可能,因为在std::cin和std::cout输入之前,c++可能会采取特殊措施刷新std:::cout?但这只是一个理论示例:如果已完全启用缓冲,用户将看不到提示符。

Such a situation can occur from time to time, though it might not be very often. Consider writing to a pipe to interact with another process. Or even if your program writes to log file and you personally look into the log file from time to time to see how it runs --- in case of buffering, you usually will not see the output that has been printed from program, but still stays in the buffer yet.

这种情况有时会发生,虽然可能不是经常发生。考虑编写一个管道来与另一个进程交互。甚至如果程序写入日志文件和你个人的日志文件不时地看看它运行——在缓冲的情况下,你通常不会看到从程序的输出打印,但仍停留在缓冲。

Another important situation to account for --- if your program severely crashes, the buffer contents might not end on the hard drive at all. (I expect the stream destructors to flush the buffer, but a crash can be so severe that no destructors will be called at all.)

另一个需要考虑的重要情况是——如果您的程序严重崩溃,缓冲区内容可能根本不会在硬盘上结束。(我预计流析构函数会刷新缓冲区,但崩溃可能非常严重,根本不会调用任何析构函数。)

#3


10  

It is preferable to flush the buffer if you need the target of your stream to receive the data before the stream is closed.

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

A real-life example would be an application log, written from a stream that's always open... You may want to look at this log while the program is still running.

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

#4


10  

First, a bit of revisionist history.

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

In the old days, when everybody used stdio.h library to do I/O, text that was viewed interactively was typically line buffered (or even unbuffered), and text that was not was fully buffered. So, if you output '\n' to the stream, it would "always" do the Right Thing: lines users were looking at get flushed and seen immediately, and lines getting dumped to file get buffered for maximum performance.

在过去,每个人都使用stdio。h库用于执行I/O,交互查看的文本通常是行缓冲(甚至是未缓冲),而未完全缓冲的文本。因此,如果您将'\n'输出到流,那么它将“始终”做正确的事情:用户正在查看的行会立即被刷新并被看到,被转储到文件的行将被缓冲以获得最大的性能。

Unfortunately, it isn't actually always the Right Thing; the runtime cannot always predict how users actually want to view the output of your program. One common trap is redirecting STDOUT -- people get used to running their program in a console and seeing the output (with its line-buffered behavior) in the console, and then for whatever reason (e.g. long running job) they decide to redirect STDOUT to a file, and are promptly surprised by the fact the output is no longer line-buffered.

不幸的是,它并不总是正确的;运行时不能总是预测用户实际希望如何查看程序的输出。一个常见的陷阱是重定向标准输出——人们习惯于在控制台运行他们的程序和输出(其line-buffered行为)在控制台,然后不管出于什么原因(例如,长时间运行的工作)他们决定将标准输出重定向到一个文件,并立即惊讶的事实不再line-buffered的输出。

I have seen weeks of supercomputer time wasted for this reason; the output was infrequent enough that the buffering prevented anyone from being able to tell how the job was progressing.

由于这个原因,我看到了数周的超级计算机浪费时间;输出的频率非常低,以至于缓冲使任何人都无法知道作业是如何进行的。

C++'s iostream library, however, was designed to make it easy to do the Right Thing here. Except when synchronizing with stdio, it doesn't do this funny "maybe line-buffered maybe fully-buffered" thing. It always uses full buffering (except when you do unbuffered stuff, of course), and if you want things flushed on newline, you do so explicitly.

然而,c++的iostream库的设计目的是使在这里做正确的事情变得容易。除了与stdio同步时,它不会做这个有趣的“也许行缓冲也许完全缓冲”的事情。它总是使用完全缓冲(当然,当您做未缓冲的事情时除外),如果您想要在换行符上刷新内容,您可以显式地这么做。

So if you're dumping a bunch of formatted text to a file that people won't be looking at until it's done, you write \n for your line breaks.

如果你将一堆格式化的文本转储到一个文件中,直到它完成之后人们才会看到它,那么你就为换行符编写\n。

But if you're writing text people might actually want to look at while you're writing it, you use std::endl for your line breaks, and it gets displayed immediately. And if you're writing several lines at once, you can even do better: use '\n' for the intermediate line breaks and std::endl for the final one (or '\n' and std::flush). Although in this setting performance usually doesn't matter so it's usually fine to just use std::endl for all of the line breaks.

但是,如果你在写文本,人们可能会在你写的时候想要看一下,你可以使用std::endl作为换行符,它会立即显示出来。如果你同时写了几行,你甚至可以做得更好:使用'\n'作为中间换行符,使用std::endl作为最后一行(或者'\n'和std::flush)。尽管在这个设置中,性能通常并不重要,所以对于所有的断行,最好只使用std::endl。

#5


5  

I hope you've lost the link to that site that you found. std::endl does not avoid buffering. It flushes whatever is in the buffer. If you need to avoid buffering, use setf(ios_base::unitbuf). That sets the stream to flush after each insertion. That's the default setting for std::clog. The reason for doing this is that the less stuff being held in the buffer, the greater the chance that critical data will have been written to the stream when the program crashes.

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

Flushing also matters for interactive programs: if you write a prompt to std::cout, it's a Good Thing if that prompt shows up on the display before the program starts waiting for input. That's done automatically when you use std::cout and std::cin, unless you've messed with the synchronization settings.

刷新对于交互式程序也很重要:如果您向std::cout编写一个提示符,那么在程序开始等待输入之前,如果该提示符出现在显示中,这将是一件好事。当您使用std::cout和std::cin时,这是自动完成的,除非您打乱了同步设置。

Many programmers seem to use std::endl as a fancy way of spelling '\n', but it's not. You don't need to flush the output buffer every time you write something to it. Let the OS and the standard library do their jobs; they'll take care of getting the output to the appropriate place in a timely manner. A simple std::cout << '\n'; is all that's needed to put a newline into the output, and sooner or later, that will show up on the display. If you need to have it show now, typically because you've written all of the output for the time being and don't want to leave the displayed information incomplete, use std::endl after the last line of the output.

许多程序员似乎使用std::endl作为拼写“\n”的奇特方式,但它不是。您不需要每次向输出缓冲区写东西时都刷新它。让操作系统和标准库完成它们的工作;他们会及时把输出送到适当的地方。一个简单的std::cout < '\n';这就是在输出中加入换行符所需要的一切,并且迟早会在显示中显示出来。如果您需要现在显示它,通常是因为您已经编写了所有的输出,并且不希望显示的信息不完整,那么在输出的最后一行之后使用std::endl。