Section 8.3. Managing the Output Buffer


8.3. Managing the Output Buffer

Each IO object manages a buffer, which is used to hold the data that the program reads and writes. When we write

     os << "please enter a value: "; 

the literal string is stored in the buffer associated with the stream os. There are several conditions that cause the buffer to be flushedthat is, writtento the actual output device or file:

  1. The program completes normally. All output buffers are emptied as part of the return from main.

  2. At some indeterminate time, the buffer can become full, in which case it will be flushed before writing the next value.

  3. We can flush the buffer explicitly using a manipulator (Section 1.2.2, p. 7) such as endl.

  4. We can use the unitbuf manipulator to set the stream's internal state to empty the buffer after each output operation.

  5. We can tie the output stream to an input stream, in which case the output buffer is flushed whenever the associated input stream is read.

Exercises Section 8.2

Exercise 8.3:

Write a function that takes and returns an istream&. The function should read the stream until it hits end-of-file. The function should print what it reads to the standard output. Reset the stream so that it is valid and return the stream.

Exercise 8.4:

Test your function by calling it passing cin as an argument.

Exercise 8.5:

What causes the following while to terminate?

     while (cin >> i) /* . . . */ 


Flushing the Output Buffer

Our programs have already used the endl manipulator, which writes a newline and flushes the buffer. There are two other similar manipulators. The first, flush, is used quite frequently. It flushes the stream but adds no characters to the output. The second, ends, is used much less often. It inserts a null character into the buffer and then flushes it:

     cout << "hi!" << flush;      // flushes the buffer; adds no data     cout << "hi!" << ends;       // inserts a null, then flushes the buffer     cout << "hi!" << endl;       // inserts a newline, then flushes the buffer 

The unitbuf Manipulator

If we want to flush every output, it is better to use the unitbuf manipulator. This manipulator flushes the stream after every write:

     cout << unitbuf << "first" << " second" << nounitbuf; 

is equivalent to writing

     cout << "first" << flush << " second" << flush; 

The nounitbuf manipulator restores the stream to use normal, system-managed buffer flushing.

Caution: Buffers Are Not Flushed if the Program Crashes

Output buffers are not flushed if the program terminates abnormally. When attempting to debug a program that has crashed, we often use the last output to help isolate the region of program in which the bug might occur. If the crash is after a particular print statement, then we know that the crash happened after that point in the program.

When debugging a program, it is essential to make sure that any output you think should have been written was actually flushed. Because the system does not automatically flush the buffers when the program crashes, it is likely that there is output that the program wrote but that has not shown up on the standard output. It is still sitting in an output buffer waiting to be printed.

If you use the last output to help locate the bug, you need to be certain that all the output really did get printed. Making sure that all output operations include an explicit flush or call to endl is the best way to ensure that you are seeing all the output that the program actually processed.

Countless hours of programmer time have been wasted tracking through code that appeared not to have executed when in fact the buffer simply had not been flushed. For this reason, we tend to use endl rather than \n when writing output. Using endl means we do not have to wonder whether output is pending when a program crashes.


Tying Input and Output Streams Together

When an input stream is tied to an output stream, any attempt to read the input stream will first flush the buffer associated output stream. The library ties cout to cin, so the statement

          cin >> ival; 

causes the buffer associated with cout to be flushed.

Interactive systems usually should be sure that their input and output streams are tied. Doing so means that we are guaranteed that any output, which might include prompts to the user, has been written before attempting to read.



The tie function can be called on either istream or an ostream. It takes a pointer to an ostream and ties the argument stream to the object on which tie was called. When a stream ties itself to an ostream, then any IO operation on the stream that called tie flushes the buffer associated with the argument it passed to tie.

     cin.tie(&cout);   // illustration only: the library ties cin and cout for us     ostream *old_tie = cin.tie();     cin.tie(0); // break tie to cout, cout no longer flushed when cin is read     cin.tie(&cerr);   // ties cin and cerr, not necessarily a good idea!     // ...     cin.tie(0);       // break tie between cin and cerr     cin.tie(old_tie); // restablish normal tie between cin and cout 

An ostream object can be tied to only one istream object at a time. To break an existing tie, we pass in an argument of 0.



C++ Primer
C Primer Plus (5th Edition)
ISBN: 0672326965
EAN: 2147483647
Year: 2006
Pages: 223
Authors: Stephen Prata

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net