Stream buffers provide the transport and character code conversion capabilities of the Standard C++ Library iostreams. A stream buffer serves as a source and/or sink for the formatting layer represented by the streams themselves. The buffer in turn sends characters on to a file or stores them directly in a string, memory array, or some other destination; it also receives characters from strings, memory arrays, and files. A stream buffer need not handle both input and output, however; it may specialize in read operations or write operations. A stream buffer might also alter or manipulate data in some appropriate way, as we'll see in Section 18.2 when we derive a new stream buffer class.
As with streams, stream buffers are organized in a class hierarchy, albeit a much simpler one. To refresh your memory, Figure 36 below repeats the class hierarchy given previously in Figure 26:
Class basic_streambuf provides the base abstraction for a one-dimensional character array with theoretically unlimited capacity. All other stream buffers derive from this class. Class basic_streambuf also defines the basic interface between streams and stream buffers. Much of this interface delegates implementation to a set of protected virtual functions that allow derived classes to determine how things actually work. While these functions in basic_streambuf all have default behavior, a basic_streambuf object is not itself useful for a transport layer, since it doesn't provide a public constructor. Instead, a more specific kind of stream buffer is derived from the basic_streambuf class.
As shown in the class hierarchy, the iostreams facility defines three different derived stream buffers. These three are used respectively for controlling input/output to files, strings, and character arrays in memory:
Class basic_filebuf provides a transport layer for interfacing streams with files.
Class basic_stringbuf provides a transport layer for interacting directly with strings in memory.
Class strstreambuf allows writing to and reading from character arrays.
Each of these derived stream buffers implements behavior specific to its task, and extends the streambuf interface to accommodate the specific needs of its source/destination. For instance, basic_filebuf provides open and close functions for performing those operations on an underlying file, and basic_stringbuf provides a str() function that returns a copy of the underlying string.
Every stream buffer implements a character array in memory that represents a portion of the data passing through the stream--the portion that is currently buffered. The buffer maintains both a put area, which contains buffered characters written to the stream, and a get area, which contains buffered characters available for reading. Either of these may be empty, depending on the type of stream (that is, read or write only), or the stream state (for example, at the end of a file).
When the put area becomes full, the characters in that area are written out using the protected virtual function overflow(). When the get area is emptied, a new set of characters is read in using the protected virtual function underflow(). In this way the actual reading and writing of characters is delegated to a derived class as necessary. For example, a filebuf has an implementation of overflow that writes characters out to a file, while a stringbuf simply copies characters into a string whenever overflow is called.
Seeking operations and the sync operation are handled in the same way. The sync operation ensures that the state of the stream buffer and the underlying source/sink are synchronized.
Class basic_streambuf defines a public interface for reading, writing, seeking, querying, and localization. Most of the public functions that define this interface actually delegate to protected virtual functions so that specific behavior is implemented by derived classes. The Class Reference contains detailed descriptions of all of these functions. Meanwhile, the public interface, and the way in which functions delegate to virtual functions, is described below:
For reading:
in_avail() returns the number of characters currently in the buffer that are available for reading, or an estimate of the number of characters available in the underlying source if the buffer is currently empty. If an estimate cannot be obtained, as is the case with the default stream cin, then this function returns -1.
snextc() moves the current position forward in the buffer one character and returns the character it now points to, or returns ios_base::eof if at end of file.
sbumpc() returns the character currently pointed to in the buffer, then increments the current position by one.
sgetc returns the character at the current position. This function does not change the current position.
sgetn(char_type* s, streamsize n) copies up to n characters from the buffer to the character array pointed to by s. This function delegates to the protected virtual function xsgetn().
Note that the last four functions all use the protected virtual function underflow to fetch new characters if none is currently available in the buffer.
sungetc and dsputbackc(char_type) both move the current pointer back one step if possible. If it's not possible to back up, say, because we're at the beginning of a buffer attached to stdin, then both functions return the result of calling the protected virtual function pbackfail(). The function sputback also returns pbackfail() if the previous character in the buffer does not match the function's argument.
For writing:
sputc(char_type c) copies the character c into the buffer at the current position and increments the position. The protected virtual function overflow(c) is called if the write area is full.
sputn(const char_type* s, streamsize n) delegates to the protected virtual function xsputn. The effect is to copy up to n characters from s into the put area of the buffer and increment the write position that many times.
For positioning:
pubseekoff and pubseekpos delegate to their respective virtual functions, seekoff and seekpos. The behavior of these is highly dependent on the type of derived stream buffer and the type of code conversion needed. See Section 9.5 on file positioning for a description of these functions with regard to filebuf.
For locales:
pubimbue(const locale&) and getloc() set and get the character code conversion properties for a stream buffer; pubimbue actually delegates to the protected virtual function imbue. pubimbue returns the previous locale for the stream buffer, the same locale that would have been returned by getloc before a call to pubimbue.
Finally, streambuf provides a function for setting its internal character buffer and another for synchronizing the buffer and the underlying source or sink. Function pubsetbuf(char_type*,streamsize) delegates to the protected virtual function setbuf, and pubsync delegates to the protected virtual function sync.
In Section 18.2 we show how to create a new kind of stream buffer by deriving from one of the existing stream buffer classes. We re-implement one of the protected virtual functions declared by streambuf in order to modify the behavior of a filebuf.
OEM Edition, ©Copyright 1999, Rogue Wave Software, Inc.
Contact Rogue Wave about documentation or support issues.