以下仅涉及 iostream 及其缓冲区对象。有关与 C 样式 I/O 相关的缓冲区的信息,请参阅@milleniumbug 的答案。
主要是因为如果尝试刷新底层缓冲区失败,您(至少通常)希望设置流的坏位。
当流与底层流交互时,流使用的还有一个稍微复杂的小舞蹈,其中流创建一个哨兵对象,然后执行一个动作,然后哨兵对象被销毁。sentry 旨在使前缀和后缀操作异常安全。
所以整体顺序是这样的:
create sentry
if that succeeds (sentry converts to true) call rdbuf()->pubsync()
if that fails (returns -1) setstate(badbit);
流缓冲区(例如 a basic_filebuf
)直接附加到底层文件系统对象——事实上,iostream 对象和底层文件对象之间的所有交互都是通过文件缓冲区完成的。如上所示,当流对象确实需要刷新缓冲区时,它所要做的就是通过调用缓冲区的pubsync()
成员函数来告诉缓冲区刷新自己。
[供参考:[ostream.unformatted]/7:
basic_ostream&flush();
效果:表现为未格式化的输出函数(如 27.7.3.6.1 第 1 段所述)。如果 rdbuf() 不是空指针,则构造一个哨兵对象。如果此对象在转换为 bool 类型的值时返回 true,则函数调用 rdbuf()->pubsync()。如果该函数返回 -1 调用 setstate(badbit) (可能会抛出 ios_base::failure (27.5.5.4))。否则,如果哨兵对象返回 false,则不执行任何操作。
返回:*this。
...和 [ofstream.cons]/2:
显式 basic_ofstream(const char* s, ios_base::openmode mode = ios_base::out);
作用:构造类basic_ofstream的对象,用basic_ostream(&sb)初始化基类,用basic_filebuf())(27.7.3.2, 27.9.1.2)初始化sb,然后调用rdbuf()->open(s, mode|ios_base ::出去)。如果该函数返回空指针,则调用 setstate(failbit)。