#include <iostream.h> typedef long streampos; typedef long streamoff; class ios : virtual public unsafe_ios, public stream_MT { public: enum open_mode { in = 0x01, // open for reading out = 0x02, // open for writing ate = 0x04, // seek to eof upon original open app = 0x08, // append mode: all additions at eof trunc = 0x10, // truncate file if already exists nocreate = 0x20, // open fails if file doesn't exist noreplace= 0x40 // open fails if file already exists };
// stream seek direction enum seek_dir { beg=0, cur=1, end=2 };
// see ios(3CC4) for remainder ...
} ;
class streambuf : public stream_MT { public: streambuf() ; streambuf(char* p, int len); void dbp() ; protected: int allocate(); char* base(); int blen(); char* eback(); char* ebuf(); char* egptr(); char* epptr(); void gbump(int n); char* gptr(); char* pbase(); void pbump(int n); char* pptr(); void setg(char* eb, char* g, char* eg); void setp(char* p, char* ep); void setb(char* b, char* eb, int a=0); int unbuffered(); void unbuffered(int);
virtual int doallocate(); virtual ~streambuf() ;
int allocate_unlocked(); char* base_unlocked(); int blen_unlocked(); char* eback_unlocked(); char* ebuf_unlocked(); char* egptr_unlocked(); char* epptr_unlocked(); void gbump_unlocked(int n); char* gptr_unlocked(); char* pbase_unlocked(); void pbump_unlocked(int n); char* pptr_unlocked(); void setg_unlocked(char* eb, char* g, char* eg); void setp_unlocked(char* p, char* ep); int unbuffered_unlocked(); void unbuffered_unlocked(int);
public: virtual int pbackfail(int c); virtual int overflow(int c=EOF); virtual int underflow(); virtual streambuf* setbuf(char* p, int len); streambuf* setbuf(unsigned char* p, in len); virtual streampos seekpos(streampos, int =ios::in|ios:out); virtual streampos seekoff(streamoff, seek_dir, int =ios::in|ios:out); virtual int sync(); };
sbufpub3CC4() 中描述了 streambuf 的公共接口。在此,我们将讨论派生可用的缓冲区类所需的受保护接口。streambuf 类仅设计用作基类,未设计用来构造 streambuf 对象。提供了三个预定义的派生缓冲区类;请参见 filebuf(3CC4)、ssbuf(3CC4)、stdiobuf(3CC4)。
一般而言,此处描述的非虚拟函数不可被覆盖;它们提供了低级别缓冲区管理功能。
在此,我们将描述虚拟函数的功能及其缺省行为。当缺省行为适合派生的缓冲区类时,不需要对函数进行覆盖。例如,除了返回 EOF 之外(缺省行为),没有输入源的缓冲区类不需要对 underflow 执行任何操作。如果缺省行为不合适,则应当提供特定于类的函数版本。例如,连接到文件的输入缓冲区应当尝试在 underflow 上读取更多数据。替换虚拟函数应当符合为 streambuf 版本指定的规范以确保依赖于此行为的其他函数可以继续工作。
streambuf 的每个受保护的成员函数使用锁定来帮助确保 streambuf 在多线程环境中正确工作。
提供了一组无锁函数,这些函数没有实施与使 streambuf 实现多线程安全相关联的锁定机制。这些函数由附加到函数名称末尾的后缀 _unlocked 予以区分。
此构造函数为空输入流创建空缓冲区。
此构造函数使用开头位于 ptr 指向的位置的 len 个字节创建一个空缓冲区或保留区(请参见下文)。
复制构造函数和赋值运算符是专用的并且未实施,以确保 streambuf 无法复制。您不希望复制 streambuf,而是希望传递指向它的指针。
可以认为 streambuf 的缓冲区具有三个部分:获取区、放置区和保留区(与缓冲区相同)。获取区包括可立即用于输入的字符。放置区存放用于输出但尚未由其最终目的地(刷新到其中)使用的字符。获取区和放置区可能不相交,也可能重叠。保留区是整个缓冲区,由获取区和放置区重叠而成。获取区和放置区可以扩展到保留区的剩余部分。在输入和输出操作过程中,获取区和放置区的大小会扩展和收缩,始终受限于缓冲区总大小。
缓冲区及其区域是由可以通过受保护的成员函数读取和设置的专用指针变量定义的。应当将指针(下文中进行了描述)看作字符间的指向;也就是说,虽然指针指“在”某个字符,但是将其视为指在该字符“正前方”更有帮助。这就与 sbufpub (3CC4) 中描述的抽象之间建立了对应关系。
返回指向保留区开头的指针。
返回紧跟在保留区末尾后的指针。从 base() 到 ebuf()-1 的空间是保留区。如果 ebuf()==base(),则流是无缓冲的。
返回指向获取区开头的指针,因此也是指向要获取的下一个字符(如果有)的指针。立即可用的字符是从 gptr() 到 egptr()-1。如果 egptr()<=gptr(),则没有字符可用。
返回紧跟在获取区末尾后的指针,即 gptr() 的最大可能值。
返回 gptr() 的最小可能值。从 eback() 到 gptr()-1 的空间可供用来将字符放回原位(备份 get 指针)。如果 eback()==gptr(),则尝试的放回操作可能会失败。
返回指向放置区开头的指针,因此也是指向所存储的下一个字符的位置的指针(如果可能)。
返回指向可用于放置区的空间开头的指针,即 pptr() 的最小可能值。从 pbase() 到 pptr()-1 的区域表示已存储在缓冲区中但尚未使用的字符。
返回紧跟在放置区末尾后的指针,即 pptr() 的最大可能值。从 pptr() 到 epptr() 的空间可立即用来存储字符,不需要执行刷新操作。
这些函数提供了设置指针的唯一方式。为确保在各个指针之间保持一致性,不允许直接访问。要指示没有区域(获取、放置、保留)可用,函数的指针参数应当全部为零。使用等同的非零指针可能会导致不当的行为。
建立保留区(缓冲区)。将 base() 设置为 buf 并将 ebuf() 设置为 end。如果 del 为非零值,则每当其他 setb() 调用更改 base() 时或者当调用 streambuf 析构函数时,缓冲区将被删除。如果 del 为零,则这些函数不会自动删除缓冲区。
建立获取区。将 eback() 设置为 back,将 gptr() 设置为 g,将 egptr() 设置为 eg。
建立放置区。将 pptr() 设置为 p 并将 epptr() 设置为 ep。
并非 streambuf 的任何非虚拟成员都会调用此函数。它尝试设置未指定缺省大小的保留区。如果已存在保留区或者如果 streambuf 被标记为无缓冲,则它将返回零并且不执行任何操作。否则,它将尝试通过调用虚拟函数 doallocate() 进行分配。它在成功时返回 1,在失败时返回 EOF。有关 unbuffered() 和 doallocate(),请参见下文。
返回保留区 ebuf()-base() 的字符的大小。
将 n(一个有符号数量)加到 get 指针,且不执行有效性检查。
将 n(一个有符号数量)加到 put 指针,且不执行有效性检查。
streambuf 具有一个专用变量,用于跟踪流是缓冲的还是无缓冲的,与是否分配了保留区无关。此变量的主要用途是控制 allocate() 是否将实际分配保留区。如果设置了此变量,则函数的第一种形式将返回非零值,否则将返回零。如果 i 为非零值,则第二种形式会设置此变量,否则将清除此变量。
将 streambuf 的所有状态变量以文本形式直接写入到文件描述符 1(标准输出)。此数据适合用于对实现进行调试。它是一个公共函数,因此可以从任何位置调用它以用于调试,虽然它在逻辑上是受保护接口的一部分。
如上所提,这些是可以或应当由专门的缓冲区类重新定义的虚拟函数。替换函数应当满足此处列出的规范以确保可能依赖于它们的其他函数正确运行。本部分还叙述了这些函数的基类版本的缺省行为。
当 unbuffered() 为零且 base() 为零时,allocate 会调用此函数。它尝试提供一个合适大小的缓冲区。在成功时,它必须调用 setb 来建立保留区,然后返回一个大于零的值。在失败时,它返回 EOF。缺省行为是使用 new 分配缓冲区。
通常,当放置区已满并且尝试存储另一字符时,将调用此函数来使用字符(将它们刷新到输出)。如果 c 不是 EOF,则 overflow 必须存储或使用字符,并且将跟在已在放置区中的那些字符之后。它在发生错误时返回 EOF,在成功时返回其他值。基类版本的缺省行为未定义,因此,每个派生类必须定义其自己的 overflow。派生类版本的正常行为是使用放置区中的字符(介于 pbase() 和 pptr() 之间的那些字符),调用 setp() 来设置一个新的放置区,然后使用 sputc() 存储 c(如果它不是 EOF)。
当尝试放回字符 c 并且放回区中没有空间时,将调用此函数,即 eback()==gptr()。如果可以处理此情况(例如通过重新放置外部设备),则 pbackfail 的派生类版本应当执行此操作并返回 c。如果无法放回字符,无论什么原因,它都应当返回 EOF。基类版本的缺省行为是返回 EOF。
有关此函数的参数、返回值和用途的描述,请参见 sbufpub(3CC4)。具体而言,如果可能,此函数修改与 gptr() 和 pptr() 相对的抽象 get 和 put 指针。如果流不支持重新放置或者如果存在任何错误,则派生类版本应当返回 EOF,否则将返回新位置。基类版本的缺省行为是返回 EOF。
有关此函数的参数、返回值和用途的描述,请参见 sbufpub(3CC4)。具体而言,如果可能,此函数修改与 gptr() 和 pptr() 相对的抽象 get 和 put 指针。基类版本的缺省行为是返回以下函数的值
sbuf.seekoff( (streamoff)pos, ios::beg, mode )
这意味着通常只需要在派生类中实现 seekoff 并继承基类 seekpos。
调用此函数将请求使用开头位于 ptr 指向的位置的 len 字节的数组作为缓冲区。将 ptr 设置为零或者将 len 设置为小于或等于零将请求无缓冲状态。派生类版本可以选择忽略该请求。如果它接受了该请求,则应当返回 sbuf 的地址,否则将返回 EOF。如果没有保留区,则基类版本的缺省行为是接受该请求。
此函数将 streambuf 与其实际字符流进行同步。派生类版本应当将放置区中的任何字符刷新到其最终目的地,并且如果可能,应当将输入缓冲区中的任何字符归还回其来源。它在发生任何错误时应当返回 EOF,在成功时应当返回零。基类版本的缺省行为是,如果没有未决的输入或输出字符(in_avail() 和 out_waiting() 都为零),则返回零,否则返回 EOF。
当获取区为空时,将调用此函数来(从某个来源)提供用于输入的字符,但是其他时候也可以调用此函数。如果获取区不为空,则它应当只返回第一个字符(不向前移动 get 指针)。如果获取区为空,则它应当建立一个新的获取区,获得新输入,并返回第一个字符(如果有)。如果没有输入字符可用,则它应当保留空的获取区并返回 EOF。基类版本的缺省行为未定义,因此,每个派生类必须定义其自己的 underflow。
filebuf (3CC4) 、 ios (3CC4) 、 ios.intro (3CC4) 、 sbufpub (3CC4) 、 ssbuf (3CC4) 、 stdiobuf (3CC4)
《C++ Library Reference》中的第 3 章 "The Classic iostream Library" 和第 4 章 "Using Classic iostreams in a Multithreaded Environment"。