你的书似乎不是很有用。
1) 输出流将其字节发送到一个 std::streambuf
,该缓冲区可能包含一个缓冲区;std::ofstream
所使用的 std::filebuf
(派生自 streambuf
)通常会被缓冲。这意味着当您输出字符时,它不一定会立即输出;它将被写入缓冲区,并且只有当缓冲区满或以某种方式明确请求时,一般通过在流上调用 flush()
(直接或间接地,通过使用 std::endl
)才会输出到操作系统。然而,这可能会有所不同;向 std::cout
输出会与 stdout
同步,并且大多数实现将更多或更少遵循 stdout
的规则来更改缓冲策略,如果输出将发送到交互式设备,则会更改缓冲策略。
无论如何,如果您不确定,并且想要确保输出真正离开您的程序,请添加一个调用 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";
如果设置了
unitbuf
,则在字符串中的所有字符输出后,流将被清空。在启动时,
std::cerr
已经设置了
unitbuf
;默认情况下,在任何其他文件上都没有设置。但您可以根据需要自由设置或取消设置它。我建议不要取消
std::cerr
上的设置,但如果
std::cout
输出到交互设备,则在那里设置它是有意义的。
请注意,这里涉及的所有内容都是
streambuf
中的缓冲区。通常,操作系统也会进行缓冲。刷新缓冲区所做的全部工作就是将字符传输到操作系统;这个事实意味着在需要事务完整性时不能直接使用
ofstream
。
当您使用
>>
从字符串或字符缓冲区输入时,
std::istream
首先跳过前导空格,然后输入直到遇到下一个空格为止。按照标准的正式术语,它会“提取”流中的字符,以便它们不会再次被看到(除非您寻找,如果流支持它)。下一个输入将从上一个输入离开的地方开始。以下字符是在缓冲区中还是仍然在磁盘上并不重要。
请注意,输入的缓冲有些复杂,因为它在几个不同的级别上发生,并且在OS级别上,它会根据设备的不同形式进行。通常,操作系统将通过扇区对文件进行缓冲,经常提前读取多个扇区。操作系统将始终返回与要求的字符数相同的字符,除非遇到文件结尾。大多数操作系统将通过行来缓冲键盘:在输入完整行之前不返回读取请求,并且在读取请求中不返回当前行的末尾之外的字符。
与
std::ostream
使用
streambuf
输出一样,输入也使用
streambuf
进行缓冲。
std::istream
使用它来获取每个单独的字符。在
std::cin
的情况下,它通常是一个
filebuf
;当
istream
请求一个字符时,
filebuf
将从其缓冲区返回一个字符,如果有的话;如果没有,则会尝试重新填充缓冲区,例如从操作系统请求512(或其缓冲区大小)个字符。响应取决于设备的缓冲策略,如上文所述。
无论如何,如果
std::cin
连接到键盘,并且您已经输入了"hello world"所有的字符最终都会被流读取。(但如果使用
>>
,会有很多您无法看到的空格。)
cout
与stdio
同步,并且默认情况下stdio
是行缓冲的。 - Yakov Galkacin >> ch
中,由于ch
是一个指向字符字符串的指针且尚未初始化,因此它是一个“野指针”,这是未定义行为。其次,使用提取运算符>>
与std::cin
一起读取时,当遇到第一个空格时会停止读取,而输入缓冲区中仍有剩余内容。 - Raindrop7stdout/stderr
上调用setvbuf
可以控制它们的缓冲(无/行/满)。根据我对标准的阅读,只要cout/cerr
与stdio
同步(默认情况下),这应该有效地设置它们的缓冲区。 - Yakov Galka