Previous fileTop of DocumentContentsIndex pageNext file
Apache C++ Standard Library User's Guide

39.2 Deriving New Stream Buffer Classes

Deriving a new stream buffer class is not commonly necessary, but it can be extraordinarily useful when specialized behavior is needed. For example, consider a log book stream that starts writing at the beginning after reaching a certain size, so that the log file does not grow infinitely. In order to implement this new class, we first need to derive a new stream buffer type. The easiest way to do this is to derive from basic_filebuf, and then reimplement one of the protected virtual functions:

//1All derived streams should have these types defined, even though they are inherited from the base, to make referring to them easy.
//2This constructor takes a size parameter that we'll use to limit the size of the log file.
//3The protected virtual function overflow(int_type) is called whenever a stream attempts to write to the stream buffer when the put area is full. We re-implement the function in order to reset the file pointer to the beginning whenever the file gets too large.

The overflow() member function is implemented as follows:

//1The conditional expression cur_size > max_size guards against infinite recursion that might occur from overflow() being called recursively from some other method, such as pubseekoff() in code block //6 below.
//2Compute the size len of the pending output sequence.
//3Determine whether the pending output sequence will exceed max_size, the maximum size of the file. If the computed value of rem is greater than zero, max_size has been reached, and rem represents the number of characters which, if output, would exceed the maximum size of the file.
//4If rem is greater than zero, temporarily remove rem characters from the end of the pending output sequence so that when the sequence is output the total length output so far will be equivalent to max_size. Save the characters removed from the pending output sequence in saved. Also, reset the size of len to correctly represent the number of characters remaining in the pending output sequence.
//5Call the overridden function overflow() to write out the pending output sequence, which is now guaranteed not to make the total number of characters output exceed max_size. Then adjust cur_size to reflect the total number of characters output so far.
//6If number of characters output so far is equal to max_size, a condition usually created in code block //4 above when an overflow condition is detected, temporarily invalidate cur_size by setting it to a value greater than its valid maximum value to prevent infinite recursion. Then seek to the beginning of the output log so that any future output will start overwriting it from the beginning.
//7If saved contains data because of an overflow condition, write the overflow data to the pending output sequence.

In order to use this new logbuf class template, we do not necessarily need a new logstream class template. But it might come in handy in some cases so we provide a definition for one just in case:

//1This private member provides us with a logbuffer object.
//2Again, we want to define the standard set of types.
//3This constructor creates a stream with the given maximum size and the given file name.
//4The const member function rdbuf() returns a non-const pointer to the logbuffer data member.

Finally, we implement our new log stream class as shown here:

//1The ios_base::init() member function initializes the base class. In part the initialization consists of installing a pointer to the logbuffer in the ios_base so base classes have access to the buffer.
//2Open the file for writing.

We can use this new log buffer class as follows:

//1Construct a logstream object, setting the maximum size of its output sequence (that is, the maximum size of the test.log file) to 256 bytes.
//2Create a character array buf of 33 characters, and set the internal character buffer maintained by the log's buffer to buf.
//3Write the integers 0 through 149 enclosed in brackets to the log stream object.

The total output exceeds 256 characters, yet the file created by the example would not exceed 256 characters. If you opened the file, you would see:

24][125][126][127][128][129][130][131][132][133][134] [135][136][137][138][139][140][141][142][143][144][14 5][146][147][148][149]8][99][100][101][102][103][104] [105][106][107][108][109][110][111][112][113][114][11 5][116][117][118][119][120][121][122][123][1

Note that the last complete number at the end of the file is 123, and that the next number, 124, is split between the end of the file ([1) and the beginning of the file (24]). This demonstrates that the output wrapped from the end of the file back to the beginning, overwriting the earlier output. The last number output, 149, overwrote the output for number 98, leaving only the last digit.

Previous fileTop of DocumentContentsIndex pageNext file