缓冲和无缓冲流

Ale*_*Dan 3 c++ stream buffered unbuffered

在缓冲流的情况下,它在一本书中说它等到缓冲区已满,然后写回监视器.例如:

cout << "hi"; 
Run Code Online (Sandbox Code Playgroud)
  1. "缓冲区已满"是什么意思.

    cerr << "hi";
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在我的书中说,发送到的所有内容都会cerr立即写入标准错误设备,这是什么意思?

    char *ch;
    cin>> ch; // I typed "hello world";
    
    Run Code Online (Sandbox Code Playgroud)
  3. 在这个例子ch中将被分配为"hello"并且"world"将被忽略是否意味着它仍然在缓冲区并且它将影响未来语句的结果?

Jam*_*nze 12

你的书似乎没什么帮助.

1)输出流将其字节发送到a std::streambuf,其中可能包含缓冲区; 使用的std::filebuf(派生自streambuf)和std::ofstream通常会被缓冲.这意味着当你输出一个字符时,它不一定立即输出; 它将被写入缓冲区,并仅在缓冲区已满时输出到OS,或者以某种方式显式请求它,通常是通过调用 flush()流(直接或间接地,通过使用std::endl).然而,这可能会有所不同; 输出std::cout与其同步 stdout,并且大多数实现将或多或少遵循stdoutfor 的规则, std::cout如果输出转到交互式设备,则更改缓冲策略.

无论如何,如果你不确定,并且你想确保输出确实离开你的程序,只需添加一个flush的调用.

2)你的书在这里错了.

缓冲策略之一是unitbuf; 这是std::ostream您可以设置或重置的标志 (std::ios_base::set()std::ios_base::unset()- std::ios_base是基类 std::ostream,因此您可以在std::ostream 对象上调用这些函数).当unitbuf设置,std::ostream增加了一个电话flush() 给每个输出功能的结束,所以当你写:

std::cerr << "hello, world";
Run Code Online (Sandbox Code Playgroud)

在输出字符串中的所有字符后,将刷新流,前提unitbuf是已设置.在启动时,unitbuf设置为std::cerr; 默认情况下,它不会在任何其他文件上设置.但您可以随意设置或取消设置.我建议不要将其取消std::cerr,但如果std::cout输出到交互式设备,那么将它设置在那里是很有意义的.

请注意,这里所讨论的只是缓冲区streambuf.通常,OS也会缓冲.所有刷新缓冲区都是将字符传输到操作系统; 这一事实意味着您无法ofstream在需要事务完整性时直接使用 .

3)当您使用输入字符串或字符缓冲区时>>,第 std::istream一个跳过前导空白区域,然后输入最多但不包括下一个空白区域.在标准的正式术语中,它从流中"提取"字符,以便不再看到它们(除非您寻求,如果流支持它).下一个输入将从前一个左侧关闭的位置拾取.以下字符是在缓冲区中还是在磁盘上,实际上是无关紧要的.

请注意,输入的缓冲有些复杂,因为它发生在几个不同的级别,而在OS级别,它根据设备采用不同的形式.通常,OS将按扇区缓冲文件,通常预先读取几个扇区.除非遇到文件末尾,否则操作系统将始终返回所需数量的字符.大多数操作系统将逐行缓冲键盘:从读取请求返回直到输入完整的行,并且永远不会在读取请求中返回超出当前行末尾的字符.

以与std::ostream使用streambuf输出相同的方式, std::istream使用一个来获取每个单独的字符.在这种情况下std::cin,它通常是一个filebuf; 当istream 请求一个字符时,filebuf如果有一个字符,它将从缓冲区返回一个字符; 如果没有,它将尝试重新填充缓冲区,从OS请求例如512(或其缓冲区大小)字符.如上所述,其将根据其对设备的缓冲策略进行响应.

无论如何,如果std::cin已连接到键盘并且您已键入"hello world",则最终将由流读取您键入的所有字符.(但是如果你正在使用>>,那么将看不到很多空白.)