Columns


Standard C/C++

The Header <ostream>

P.J. Plauger


P.J. Plauger is senior editor of C/C++ Users Journal. He is convenor of the ISO C standards committee, WG14, and active on the C++ committee, WG21. His latest books are The Draft Standard C++ Library, and Programming on Purpose (three volumes), all published by Prentice-Hall. You can reach him at pjp@plauger.com.

Introduction

I continue my detailed review of iostreams. The previous two columns were on the header <istream>. It defines the class istream, which you need to extract characters from an input stream. (See "Standard C: The Header <istream>," CUJ, July 1994, and "Standard C: Extractors," CUJ, August 1994.)

This month, I switch to its companion header <ostream>. As you might guess, it defines the class ostream, which helps you insert characters into an output stream. Class ostream is the obvious complement to class ostream. I have intentionally modeled this discussion after that of its predecessor, to highlight the structural similarities.

For convenient reference, Listing 1 shows how the draft C++ Standard defines the class ostream. You might want to look it over now, then refer back to it as needed in the discussion that follows.

Class ostream, like istream, is derived from the virtual public base class ios. The best known object of this class is cout, which controls output to the standard output stream — the same C-style stream controlled by stdout, declared in <stdio.h>. You can also create ostream objects that control files you open by name, or strings of text stored in memory, as later columns will reveal.

Most of the ostream member functions fall into one of two broad categories:

The former group uses the name put and overloads the name write. It is analogous to the Standard C library's fputc and fwrite, declared in <stdio.h>, but a bit easier to use. For example, you can insert an arbitrary character sequence with:

   if (cout.write(buf, n))
      <output succeeded>
The test is true (nonzero) only if the member function successfully inserts all n characters from buf to the stream controlled by the ostream object cout.

The latter group of member functions overloads operator<< to make the basic family of inserters. It is analogous to the Standard C library's fprintf and friends, but with a variety of advantages. For example, you can insert an octal integer with:

   int n;
   if (cout << oct << n)
      <output succeeded>
The test is true only if the second inserter inserts all the characters required to represent the int value n as an octal integer in text form.

Inserters are the single most popular selling point for iostreams over more conventional Standard C input and output. (Extractors are a close second.) But they are easier to explain after you gain more familiarity with the unformatted output functions. I return to inserters in more detail next month.

Prefix and Suffix Functions

Remember that all extractions and insertions in iostreams are mediated by objects of class streambuf. (See "Standard C: The Header <streambuf>," CUJ, June 1994.) There is one small problem, however. It is perfectly permissible for the pointer to streambuf to be null. It is also quite possible that the pointer is non-null, but the stream is in some error state that should discourage inserting. Thus, it behooves any output function to look before it leaps. The canonical way to play safe is to wrap every inserter member function with two calls to ostream member functions:

   if (opfx())
      <perform any output>
   osfx();
The "prefix" function opfx(int) verifies that the stream is both ready and willing to accept output, or at least to support calls to the streambuf member functions. It also performs other initialization operations.

The "suffix" function osfx( ) performs any necessary wrapup operations after each output member function does its work. In particular, if the format flag unitbuf is set, the function flushes the associated stream buffer. Such "unit buffering" is often a happy compromise between the better performance of full buffering and the tighter synchronization with external files of no buffering at all. If you write an output function that uses the ostream object x and makes direct calls to its associated streambuf object, always call x.opfx() and x.osfx() as shown above.

Inserters must also handle exceptions, for much the same reasons that extractors do. (See the July 1994 installment, described above.) Any call to rdbuf()->sputc( ) can result in a call to the virtual member function streambuf::overflow, which can be a programmer-supplied virtual member function for a derived class. So as with extractors, the library can never know when a call on a streambuf member function might throw an exception.

The draft C++ Standard says that when an exception occurs during execution of an output (or input) member function the function must call setstate(badbit), then rethrow the exception. The structure of an arbitrary output function must now look like:

   try {
      if (opfx())
         <perform any output>
      osfx();
      }
   catch (...) {
      setstate(badbit);
      throw;
      }
Note once again that the act of setting badbit can also raise an exception, of class ios::failure. (See "Standard C: The Header <ios>," CUJ, May 1994.) Should that happen, the original exception never gets rethrown.

Unformatted Output Functions

Now you have enough background to understand how the unformatted output functions work. The simplest of these is the member function put(char). It inserts a single character — probably by calling rdbuf()->sputc(char) inside the sandwich shown above — and delivers it as the value of the function. A failure to insert the requested character, for any reason, is reflected in a return value of EOF.

Obviously, the overhead for inserting a single character via put(char) is substantially higher than for the Standard C library function putchar(int), declared in <stdio.h>. The latter is almost invariably implemented as a macro that stores a character straight into an output buffer more often than not. Thus, it behaves much like streambuf::sputc(char). But ostream::put(char) is almost impossible to treat similarly, given the prefix/suffix calls and exception handling required by the draft C++ Standard. You should thus favor methods that insert many more characters for each call, whenever possible, if performance is an issue.

If you want rather less logic per character, consider the member function write(const char *, int) (or its alternate forms for constant arrays of signed char or unsigned char). It simply inserts characters until a count is exhausted, or until no more characters can be inserted.

For still faster copying from another stream buffer, consider the inserter operator<<(streambuf&). Actually a formatted input function, it extracts characters from its stream buffer argument and writes them directly to the stream buffer controlled by the ostream object. Thus, you can write:

cout << *cin.rdbuf();
to copy the remaining characters from cin directly to cout. In this case, copying can be quite fast. Related istream member functions can copy up to, but not including, a delimiter you specify.

The member function flush() simply calls the public "synchronizing" function rdbuf()->pubsync() (assuming the associated streambuf object is present). Typically, such an operation flushes an output stream to the associated external file. Several mechanisms exist to ensure that synchronization occurs at judicious times:

And, of course, the stream buffer will be flushed when it is destroyed. You need call flush() for an ostream object only if you can't be certain that timely synchronization will occur in the normal course of affairs.

Using <ostream>

You have little or no occasion to include the header <ostream> directly. Like <ios>, <streambuf>, and <istream>, described in earlier installments, it is another header invented by the Committee simply to split the iostreams declarations into more manageable pieces. But the chances are just as good that you'll use the contents of <ostream> in a program. Class ostream is the base class for all classes that support insertions into a stream buffer, the classic way to mediate all output in the iostreams package. The base class summarizes what is common to all such output classes.

If you include the header <iostream>, you can use the ostream object cout to write the standard output stream. Similarly, you can use the ostream objects cerr or clog to write the standard error stream. Otherwise, you typically create an object derived from ostream to mediate output to a stream buffer you create at the same time. (The Standard C++ library does so in the headers <strstream>, <sstream>, and <fstream>.)

The only occasion you have for declaring an ostream object directly is to mediate output to a stream buffer created separately. You can, for example, set up a bidirectional stream various ways. I repeat here the way I showed a while back:

#include <fstream>
   .....
   ifstream istr("abc", ios::in | ios::out);
   ostream ostr(istr.rdbuf());
or:
#include <fstream>
   .....
   ifstream istr("abc", ios::in | ios::out);
   ostream ostr;
   ostr.rdbuf(istr.rdbuf());
Given an ostream object x, you can perform a whole host of operations on it. Many are inherited from the base class ios, which I described several months back. (May 1994, as before.) You can also call:

I deal with the first two groups here. The next two are covered as part of next month's essay.

Predefined Manipulators

All the manipulators defined for class ios also apply to objects of class ostream, naturally enough. The same is true for the ios member functions that have the same effect as the manipulators. Not all have meaningful effect, however. For an ostream object, the relevant information depends on the scalar type being inserted. I describe the particulars later, with the inserters for each group of types.

One flag affects all formatted and unformatted output functions. The format flag unitbuf calls for the output stream to be flushed by a call to the suffix function ostream::osfx(). The following formatting information affects all the string and scalar formatted output functions, except for the three character types:

The "internal" point in a numeric conversion is generally where you would add leading zeros, or those * characters on checks. For a hexadecimal conversion, it is to the right of the 0x or 0X prefix. For all others, it is immediately before the leading digit.

The header <ostream> declares two peculiar member functions:

ostream& operator<<(ostream& (*pf)(ostream&));
ostream& operator<<(ios& (*pf)(ios&));
It is the magic that makes the manipulators defined for class ios work as "pseudo-extractors" with ostream objects. The first supports manipulators intended to work only with ostream objects.

Three such creatures are defined by the Standard C++ library, all declared in <ostream>. (The template class omanip, defined in <iomanip), also defines manipulators for ostream objects.) You can write:

x << endl;
to insert a newline character ('/n') and flush the output stream. This inserter is both a convenient shorthand and a useful way to synchronize the output stream periodically with an interactive file, such as a terminal display.

Similarly, the manipulator ends inserts a null character ('\0') without flushing the stream. You use this manipulator primarily to insert a terminating null character after generating an in-memory character sequence.

The manipulator flush flushes the output stream without inserting a character. You use this manipulator only when you can't be certain that a necessary synchronization has occurred.

Character Output Functions

Class ostream provides several member functions for inserting sequences of one or more characters. Here is my attempt to characterize them all in a way that highlights their critical differences. Each of the member functions that follows:

With those blanket rules in mind, here is the list of functions you might use to insert sequences of characters:

Conclusion

I can't counsel you on which of these member functions to use. That decision depends heavily on the particular need, and the style of programming you favor. I do suggest as before, however, that you pick one or two of these choices, learn them well, and stick with them.

The unformatted output functions are far less extensive than their cousins, the unformatted input functions. The latter group has many options for parsing input, if only to look for delimiter characters. Unformatted input functions also have to worry about end-of-file during extractions, and how best to respond to it. By contrast, the unformatted output functions know exactly what they want to insert. The failure of any insertions is generally considered a disastrous error, not some condition to work around.

Even so, class ostream offers a rich assortment of options just for inserting uninterpreted character data. It's easy to get befuddled by all the choices.