缓冲和未缓冲的流
Buffered and unbuffered stream
在缓冲流的情况下,它在一本书中说它等到缓冲区已满后再写回监视器。例如:
cout << "hi";
他们所说的"缓冲区已满"是什么意思。
cerr << "hi";
我的书中说,发送到
cerr
的所有内容都会立即写入标准错误设备,这是什么意思?char *ch; cin>> ch; // I typed "hello world";
在此示例中,
ch
将被分配给"hello",而"world"将被忽略,这是否意味着它仍在缓冲区中,并且会影响未来语句的结果?
你的书似乎不是很有帮助。
1(输出流将其字节发送到std::streambuf
,该可能包含缓冲区;使用的std::filebuf
(派生自streambuf
并且std::ofstream
通常会被缓冲。 这意味着当你输出一个字符,它不一定立即输出;它将写入缓冲区,并仅在缓冲区完整,或者您以某种方式明确请求它,通常通过调用 flush()
流上(直接或间接地使用 std::endl
(。但是,这可能会有所不同;输出到std::cout
与 stdout
,大多数实现或多或少会遵循 stdout
对于std::cout
,如果输出,则更改缓冲策略将转到交互式设备。
无论如何,如果您不确定,并且希望确保输出确实会离开您的程序,只需添加一个调用即可刷新。
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
。 启动时,unitbuf
已设置对于std::cerr
;默认情况下,它不会在任何其他文件上设置。 但是你可以根据需要自由设置或取消设置。 我会建议反对在std::cerr
上取消设置,但如果std::cout
输出到交互式设备,将其设置在那里很有意义。
请注意,这里所讨论的只是streambuf
中的缓冲区。通常,操作系统还会缓冲。 刷新缓冲区所做的所有操作都是将字符传输到操作系统;这一事实意味着您不能使用 ofstream
直接在需要事务完整性时。
3( 当您使用 >>
输入字符串或字符缓冲区时, std::istream
首先跳过前导空格,然后输入但不包括下一个空格。 在正式条款中标准,它从流中"提取"字符,以便它们不会再被看到(除非您寻求,如果流支持它(。下一个输入将从上一个停止的地方拾取。 是否以下字符在缓冲区中,或者仍在磁盘上,真的是不切题的。
请注意,输入的缓冲有些复杂,因为它会发生在几个不同的级别,在操作系统级别,它需要不同的形式取决于设备。 通常,操作系统将通过以下方式缓冲文件部门,经常提前阅读几个部门。 操作系统将始终返回所需数量的字符,除非遇到结尾文件。 大多数操作系统将按行缓冲键盘:不从读取请求,直到输入完整行,并且从不返回读取请求中当前行尾以外的字符。
与std::ostream
使用streambuf
进行输出的方式相同, std::istream
使用一个来获取每个单独的角色。 在这种情况下std::cin
,它通常是一个filebuf
;当istream
请求一个字符,filebuf
如果它有一个;如果没有,它将尝试重新填充缓冲区,请求例如 512(或其缓冲区大小(字符操作系统。 它将根据其缓冲策略进行响应设备,如上所述。
无论如何,如果std::cin
连接到键盘,并且您已经键入"hello world"
,将读取您键入的所有字符最终在溪流旁。 (但是如果你使用>>
,会有很多您不会看到的空白。
C++中的流是缓冲区以提高效率,也就是说,与内存操作相比,文件和控制台IO非常慢。
为了解决这个问题C++流有一个缓冲区(内存库(,其中包含要写入文件或输出的所有内容,当它已满时,它会刷新到文件。输入则相反,当缓冲区耗尽时,它会获取更多。
这对于流来说非常重要,因为以下
std::cout << 1 << "hello" << ' ' << "worldn";
将是 4 次写入一个效率低下的文件。
但是,在 std::cout、cin 和 cerr 的情况下,这些类型实际上默认关闭了缓冲,以确保它可以与 std::p rintf 和 std::p uts 等结合使用。
要重新启用它(我建议这样做(:
std::ios_base::sync_with_stdio(false);
但是不要在设置错误时使用 C 样式控制台输出,否则可能会发生不好的事情。
您可以使用一个小应用程序自己查看差异。
#include <iostream>
int main() {
std::cout<<"Start";
//std::cout<<"Start"<<std::endl; // line buffered, endl will flush.
double j = 2;
for(int i = 0; i < 100000000; i++){
j = i / (i+1);
}
std::cout<<j;
return 0;
}
尝试两个"开始"语句的区别,然后更改为 cerr。 您注意到的差异是由于缓冲造成的。
for-语句在我的装备上大约需要 2 秒,您可能需要调整您的 i <条件。>
1("缓冲区已满"是什么意思。
对于缓冲输出,有一个内存区域,称为缓冲区,您写出的内容在实际写入输出之前被存储。当您说cout << "hi"
字符串可能只复制到该缓冲区中,而不是写出。cout 通常等到内存填满后才真正开始写出内容。
原因是,通常开始实际写入数据的过程很慢,所以如果你对每个角色都这样做,你会得到糟糕的性能。使用缓冲区,以便程序只需要不经常这样做,您就可以获得更好的性能。
2(它在我的书中说,发送到CERR的所有内容都会立即写入标准错误设备,这是否意味着它发送"H"然后"I"......?
它只是意味着不使用缓冲区。 cerr 可能仍会同时发送"h"和"i",因为它已经同时拥有它们。
3(在这个例子中,ch将被分配给"hello",而"world"将被忽略,这是否意味着它仍然在缓冲区中,它会影响未来语句的结果?
这与缓冲没有任何关系。 运算符 char*>>定义为读取直到看到空格,因此它停止在"hello"和"world"之间的空格处。但是,是的,下次阅读时,您将获得"世界"。
(尽管如果该代码不仅仅是 actuall 代码的释义,那么它具有未定义的行为,因为您正在将文本读取到未定义的内存位置。相反,您应该执行以下操作:
std::string s;
cin >> s;
(
-
每次调用写入终端的速度都很慢,因此为了避免执行缓慢的操作,通常会将数据存储在内存中,直到输入了一定数量的数据或使用 fflush 或 std::endl 手动刷新缓冲区。这样做的结果是,有时文本可能不会在您期望的时刻写入终端。
-
由于错误消息的计时比正常输出更为关键,因此将忽略性能影响,并且不会缓冲数据。但是,由于字符串是在单个数据片段中传递的,因此它是在一次调用中写入的(在某处的循环中(。
-
它的世界仍然在缓冲区中,但是通过在 3 行程序中尝试它来自己证明这一点非常容易。但是,您的示例将失败,因为您正在尝试写入未分配的内存。你应该把输入到一个std::string中。
- 如何使用原子指针执行双缓冲
- 消费者和生产者问题的双重缓冲
- 如何检测是否在缓冲绘画动画中绘制最后一帧?
- 我似乎无法修改帧缓冲
- 如何在C++中写入 1000 个文件时有效地缓冲
- 帧缓冲纹理变为白色(片段着色器不会影响它)
- 我是否使用双缓冲?
- OpenGL:使用实例化绘图与我正在绘制的帧缓冲进行绘制
- 如何强制文件描述符缓冲我的输出
- Qt双缓冲行为
- 如何在没有缓冲的情况下使用 parquet-cpp 写入面向流/行的数据?
- MySQL 事务和缓冲的请求列表
- 使用 std::stringbuf 进行缓冲的效果,同时通过插入运算符'<<'执行写入
- Qt 帧缓冲对象甚至不渲染顶点
- MySQL连接器C 结果集被缓冲
- w/ w/结构带char缓冲液的静态初始化[]
- 在 Linux 中禁用 USB 大容量存储设备的读取缓冲
- 是否有一种缓冲方法进行同步
- 双缓冲的waveoutwrite()像地狱一样口吃
- std :: ofstream-没有比1023(即时冲洗)更长的缓冲字符串