C ++ cout和cin缓冲区,以及缓冲区 [英] C++ cout and cin buffers, and buffers in general

查看:223
本文介绍了C ++ cout和cin缓冲区,以及缓冲区的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人可以更明确地解释缓冲区的概念吗?我理解缓冲区是存储字符的数据结构,以及要读取数据的位置。刷新缓冲区的想法是什么?

Can someone explain the concept of buffers a bit more explicitly? I understand that buffers are data structures where characters are stored, and the place where the data is to be read from. What is the idea of flushing buffers?

当缓冲区被刷新时,这是指写入存储在其中的字符的行为吗?

When a buffer is flushed, is this referring to the act of writing the characters stored in it?

从文本:

To avoid the overhead of writing in response to each output request, the library uses the 
buffer to accumulate the characters to be written, and flushes the buffer, by writing its
contents to the output device, only when necessary. By doing so, it can combine several 
output operations into a single write.

当引用'flushing'时,几乎让它听起来好像缓冲区正在被写入,与此同时。只是猜测。

When referring to 'flushing' that almost makes it sound as if the buffer is being written but also erased at the same time. Just speculation.

因此,为了写入在屏幕上查看,需要缓冲区刷新?

So, in order to be wrote to view on a screen the buffer flush is required?

When our program writes its prompt to cout, that output goes into the buffer associated
with the standard output stream. Next, we attempt to read from cin. This read flushes
the cout buffer, so we are assured that our user will see the prompt.

在这里,它听起来像是通过使用'endl'告诉系统它需要

Here, it sounds as if the by using 'endl' at the end it tells the system it needs to write immediately(implying otherwise is wouldn't?) What is endl is not used?

Writing the value of std::endl ends the line of 
output, and then flushes the buffer, which forces the system to write to the output 
stream immediately.


推荐答案

缓冲的基本想法是将操作合并为更大块:读取整个页面,并且根据请求使它可用;而不是读取小的字节数,而不是写少量的字节,缓冲它们并写整个页面或当显式请求写入时。基本上,这是一个重要的性能优化。它对于I / O操作非常清楚,但通常也适用于其他用途:一次处理多个单元通常比处理单个单元更快。

The basic idea of buffering is to combine operations into bigger chunks: instead of reading small number of bytes, read an entire page and make this available as requested; instead of writing small number of bytes, buffer them up and write an entire page or when writing is explicitly requested. Essentially, this is an important performance optimization. It pretty clear cut for I/O operations but generally applies for other uses as well: processing multiple units at once generally ends up to be faster than processing individual units.

相对于I / O 刷新是指将当前缓冲的字节写入其目的地 - 无论这在实践中是什么意思。对于C ++ IOStreams刷新一个流等于调用成员函数 std :: ostream :: flush(),它依次调用 std :: streambuf :: pubsync()在关联的流缓冲区(这忽略了流实际上是类模板的细节,例如 std :: basic_ostream< cT,traits> ;为了这个讨论的目的,它们并不重要,他们是类模板):基类 std :: streambuf 是C ++的抽象如何一个特定的流是被处理。它在概念上包括输入和输出缓冲器加上负责读取或写入缓冲器的虚拟功能。函数 std :: streambuf :: pubsync()调用虚函数 std :: streambuf :: sync()其应该被可能缓冲字符的每个流缓冲器重写。

With respect to I/O flushing refers to writing the currently buffered bytes to its destination - whatever this means in practice. For C++ IOStreams flushing a stream amounts to calling the member function std::ostream::flush() which in turn calls std::streambuf::pubsync() on the associated stream buffer (this ignores the detail that the stream are actually class templates, e.g. std::basic_ostream<cT, traits>; for the purpose of this discussion it doesn't matter that they are class templates): the base class std::streambuf is C++'s abstraction on how a certain stream is to be processed. It conceptually consists of an input and an output buffer plus virtual function responsible for reading or writing the buffers, respectively. The function std::streambuf::pubsync() calls the virtual function std::streambuf::sync() which should be overridden for every stream buffer which potentially buffers characters. That is, what flushing actually means depends on how this virtual function is implemented.

sync()是否覆盖实际上做了什么,它的作用显然取决于流缓冲区表示什么。例如,对于负责读取或写入文件的 std :: filebuf sync()写入缓冲器的当前内容并从缓冲器中移除刷新的字符。假设文件可能不真正表示物理文件,但例如。一个命名管道与不同的进程通信,这是合理的行为。另一方面,刷新 std :: stringbuf 这是用于实现写入 std :: string 使用eg通过 std :: ostringstream 实际上不做任何事情:字符串是完全在程序和 std :: string 表示其值是在 std :: stringbuf :: str()成员函数被调用时构造的。对于用户定义的流缓冲区,有许多不同的行为。一种常见类型的流缓冲器在将其传递到另一流缓冲器之前以某种方式过滤输出(例如,记录缓冲器可在每一新行之后添加时间戳)。这些通常只调用下一个流缓冲区的 std :: streambuf :: pubsync()函数。

Whether an override of sync() actually does something and what it does clearly depends on what the stream buffer represents. For example, for a std::filebuf which is responsible to reading from or writing to a file, sync() writes the current content of the buffer and removes the flushed characters from the buffer. Given that a file may not really represent a physical file but e.g. a named pipe to communicate with a different process, this is reasonable behavior. On the other hand, flushing a std::stringbuf which is the stream buffer used to implement writing to a std::string used e.g. by std::ostringstream actually doesn't do anything: the string is entirely within the program and the std::string representing its value is constructed when the std::stringbuf::str() member function is called. For user defined stream buffers there are many different behaviors. A common class of stream buffers is filtering the output somehow before passing it on to another stream buffer (e.g. a logging buffer may add a time stamp after each newline). These typically just call the std::streambuf::pubsync() function of the next stream buffers.

,对实际行为的描述通常保持相当模糊,因为它不是真正清楚究竟发生了什么。从概念上讲,刷新流或者在流缓冲区上调用 pubsync()应该更新字符的外部目的地以匹配当前内部状态。通常,这相当于转发当前缓冲的字符并将其从内部缓冲器中移除。在这一点上,值得注意的是,缓冲区通常也会在它刚刚满时写入。当它完全取决于特定的流缓冲区。 std :: filebuf 的一个好的实现将基本上填充匹配基础页面大小(或其倍数)的字节缓冲区,然后写入完整页面,的I / O操作(这实际上是相对棘手的,因为缓冲区大小在不同的文件系统之间是不同的,并且取决于使用的编码,当写入产生的字节数不能容易估计)。

Thus, descriptions of the actual behavior are typically kept fairly vague because it isn't really clear what exactly happens. Conceptually, flushing a stream or calling pubsync() on a stream buffer should update the external destination of the character to match the current internal state. Generally, this amounts to forwarding the currently buffered characters and removing them from the internal buffer. At this point it is worth noting that the buffer typically also gets written when it is just full. When it gets full depends, again, on the particular stream buffer. A good implementation of std::filebuf will essentially fill a buffer of bytes matching the size of the underlying page (or a multiple thereof) and then write complete pages, minimizing the number of I/O operations needed (this is actually relatively tricky to do because buffer sizes are different between different file systems and depending on the encoding used when writing the number of produced bytes can't be easily estimated).

标准C ++库通常不需要显式刷新:

The standard C++ library typically doesn't require explicit flushes:


  • std :: cerr 设置为自动刷新每个输出操作调用后产生的任何输出。这是默认设置的格式化标志 std :: ios_base :: unitbuf 的结果。要关闭此功能,您可以使用 std :: cerr<< std :: nounitbuf 或者你可以使用 std :: clog ,它写入同一个目的地但不执行这个刷新。 li>
  • std :: istream 中读取 std :: ostream ,如果有的话,被刷新。默认情况下, std :: cout 绑定到 std :: cin 。如果你想设置一个绑定 std :: ostream 自己,你可以使用例如。 in.tie(& out)或者,如果你想删除一个绑定的 std :: ostream 例如 std :: cin.tie(0)

  • std :: ostream 被销毁(或者当 std :: ostream 是其中一个标准流时,它通常会被销毁), std ::当流的缓冲区溢出虚拟函数 std :: streambuf :: overflow() $ c>被调用,它通常将当前缓冲区的缓冲区(加上传递的字符,如果有的话)写入其目的地。这通常通过调用 sync()来清除当前缓冲区,但是完全取决于具体的流缓冲区。

  • The stream std::cerr is set up to automatically flush any output produced after each output operations being called. This is the result of the formatting flag std::ios_base::unitbuf being set by default. To turn this off you can use std::cerr << std::nounitbuf or your can just use std::clog which writes to the same destination but doesn't to do this flushing.
  • When reading from an std::istream the "tied" std::ostream, if any, is flushed. By default std::cout is tied to std::cin. If you want to set up a tied std::ostream yourself you can use e.g. in.tie(&out) or, if you want to remove a tied std::ostream you can use e.g. std::cin.tie(0).
  • When an std::ostream is destroyed (or when it would normally destroyed in case the std::ostream is one of the standard streams), the std::ostream is flushed.
  • When a stream's buffer would overflow the virtual function std::streambuf::overflow() is called which typically writes the buffer of the current buffer (plus the passed character, if any) to its destination. This often is done by just calling sync() to clear out the current buffer but what is done exactly, again, depends on the concrete stream buffer.

您还可以显式请求刷新 std :: ostream

You can also explicitly request flushing an std::ostream:


  • 您可以调用成员函数 std :: ostream :: flush(),例如 std :: cout.flush()

  • 您可以调用成员函数 std :: streambuf: :pubsync(),例如 std :: cout.rdbuf() - > pubsync()(假设有一个流缓冲区设置;调用 std :: ostream

  • 您可以使用操纵器 std :: flush ,例如 std :: cout<< std :: flush

  • 您可以使用操纵器 std :: endl std :: cout<< std :: endl 首先写一个换行符,然后刷新流。请注意,当您真的要刷新输出时,应该使用 std :: endl 不要使用 std :: endl ,当您实际只想创建一行结束!

  • You can call the member function std::ostream::flush(), e.g. std::cout.flush().
  • You can call the member function std::streambuf::pubsync(), e.g. std::cout.rdbuf()->pubsync() (assuming there is a stream buffer set up; calling std::ostream::flush() will do nothing if there is no stream buffer).
  • You can use the manipulator std::flush, e.g. std::cout << std::flush.
  • You can use the manipulator std::endl, e.g. std::cout << std::endl to first write a newline character followed by flushing the stream. Note that you should use std::endl only when you really mean to flush the output. Do not use std::endl when you actually just want to create an end of line! Just write a newline character for the latter!

在任何情况下,如果你只是写了几个字符,不会导致流缓冲区的缓冲区溢出,它们将不会发生,直到它们被隐式或显式刷新。通常,这不是问题,因为缓冲输出需要变得可用的正常情况,即从 std :: cin 读取时,由 std :: cout tie() d到 std :: cin 。当使用其他I / O机制时,可能需要显式地 tie()相关流。如果程序在调试期间崩溃或断言,则缓冲器有时是问题,因为对流可能已经进行了一些输出,但尚未发送。对此的补救措施是使用 std :: unitbuf

In any case, if you just write a couple of characters which don't cause the stream buffer's buffer to overflow, nothing will happen with them until they are either implicitly or explicitly flushed. Generally, this isn't a problem because the normal case where buffered output needs to become available, i.e. when reading from std::cin, is handled by std::cout being tie()d to std::cin. When there are other I/O mechanisms being used it may be necessary to explicitly tie() related streams. The buffer is sometimes a problem if the program "crashes" or asserts during debugging because some outputs to a stream may have been made but weren't, yet, sent. The remedy for this is to use std::unitbuf.

这篇关于C ++ cout和cin缓冲区,以及缓冲区的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆