P.J. Plauger is senior editor of C/C++ Users Journal. He is convener 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
The header <iostream> declares four objects:
These objects are constructed for you, so they offer a particularly easy way to perform input and output in a C++ program. The three objects that are unbuffered also support reads and writes that are properly synchronized with any C file operations that the program may also perform on the standard streams. I described buffered and unbuffered operations on stream buffers in conjunction with the header <fstream>. (See "Standard C/C++: The Header <fstream>," CUJ, April 1995 and "Standard C/C++: Implementing <fstream>," CUJ, May 1995.
- cin, to control the unbuffered standard input stream (as does stdin)
- cout, to control the unbuffered standard output stream (as does stdout)
- cerr, to control the unbuffered standard error stream (as does stderr)
- clog, to control the buffered standard error stream (as does stderr)
The header <iostream> is in many ways the culmination of all the iostreams machinery that I have described over the past year or so. Historically, in fact, the header <iostream.h> includes everything represented here in the headers <ios>, <streambuf>, <istream>, <ostream>, and <iostream>. The general assumption has been that, if you want to work with any part of iostreams, you certainly want to declare cin and friends as well.
Early Construction
The four objects declared in <iostream> also share a peculiar property. They are all constructed before any expression that accesses them, even if that expression is in a constructor for a static object. Equally, none of these objects is destroyed, at least until after the execution of the last expression that accesses them, even if that expression is in a destructor for a static object. That means you can read and write the standard streams before main is called and after main returns. At the very least, such latitude is very convenient for debugging.Pulling it off takes a bit of trickery, however. Consider the problem. Unless the Standard C++ library indulges in some extra-linguistic magic, <iostream> must contain declarations something like:
extern istream cin; extern ostream cout; extern ostream cerr; extern ostream clogOne of the object modules linked to form a program must define these objects, if any other object module refers to them. Say a constructor for the static object x extracts characters from cin. Then cin must be constructed before x is. But C++ defines no ordering among object modules for the calling of constructors for static objects. The language cannot guarantee that the two objects are constructed in the proper order.Fortunately, the language does define the ordering of constructor calls within a given object module. It promises to construct objects in the order in which they appear in the translation unit that defines the object module. You can't define cin early in each translation unit exactly one instance of the object must occur throughout the entire program. But you can define something early enough to give you a fighting chance.
Class ios: :Init
That something is an object of class ios::Init. I promised a year ago that I'd return to this nested class, and at last I have. (See "Standard C/C++: The Header <ios>," CUJ, May 1994.) An important part of the trick to constructing cin and friends is an additional declaration in <iostream>. It looks something like:
static ios::Init_Ios_init;This declares an object with the secret name _Ios_init, local to the translation unit. Because the name doesn't have external linkage, each translation unit that includes <iostream> declares a separate instance of the object. Because class ios::Init defines a default constructor, that constructor gets called to initialize the object. And because you must include a header before you make any reference to anything it declares or defines, that default constructor gets called in each translation unit before any static constructor can execute that references cin and friends.So far so good. A mechanism exists to get control in time. Presumably, it can ensure that cin and friends are properly constructed. For that, you can use a placement new expression. (See "Standard C: C++ Language Support Library," CUJ, March 1994.) Say, for example, you want to construct cin with the single-argument constructor that specifies a pointer to the stream buffer fin. You can then write:
new (&cin) istream(&fin);The effect is as if you had originally defined cin by writing:
istream cin(&fin);But this raises another problem. The definition for cin is also going to call a constructor. Either the definition will occur before the placement new expression executes or after it:
The only scenario that works is to have the definition call a constructor that does nothing at all. Then it doesn't matter whether the definition occurs before or after. So long as the placement new expression does any necessary initializing before the first use of the object, everything works fine. Classes ios, istream, ostream, and who knows what else must each have a constructor that does nothing. For much the same reason, each of these classes must also have an empty (virtual) destructor. Otherwise, a critical object might be destroyed before it is accessed from the destructor for another static object.
- Say the definition occurs first. If it does anything nontrivial such as allocating storage and storing a pointer to it in the constructed object the placement new is going to stomp all over the result. This is bad hygiene.
- Say the placement new expression occurs first. If the definition later stores much anything at all in the object, it will mess up the effect of the placement new. This is disastrous.
The final trick is to avoid constructing cin and friends too many times. It's bad enough to have to double construct so many important objects within the iostreams package. You certainly don't want to construct them all once for each translation unit in a program that includes <iostream>. Class ios::Init again comes to the rescue by defining a static member object for counting constructor calls, as in:
static int _Init_cnt;Such a member object is shared across all objects of class ios::Init. Say the member object is initialized to -1, and that the constructor for ios::Init increments this common counter each time it is called. Then a given call to the constructor knows whether it is the first such call. The counter increments to zero only on that first call. And that is the call that does the actual construction of cin and friends (and any support objects). This trick is known as the "nifty counter" technique. With just a little more logic, the nifty counter also can tell when to flush all the output streams, in preparation for program termination.So there's at least one way to ensure that cin and friends have such an extraordinarily useflifetime. The trick is clever enough, but you might still wonder why the draft C++ Standard spells out so much of the machinery. Why not leave it to each implementation to solve the problem in its own way, under the hood as it were.?
Limitations
As it turns out, situations can arise where even all this trickery fails to deliver. Say the function f is defined in one translation unit and is called during the construction of a static object in another translation unit. If f wants to extract from cin, it needs to be sure that cin has been properly constructed, as described above. But calling a function in a translation unit does not ensure that static constructors for that translation unit have first been called. The nifty counter supplied by the header <iostream> may not come through in time.The fix is to explicitly initialize an ios::lnit object within f, as in:
void f() { // read during static construction ios::Init not_otherwise_used; <can now reference cin, etc> }If this mechanism were not spelled out in the draft C++ Standard, there would be no way to solve the initialization problem portably.
Recent Changes
Once again, I note that a major recent change to iostreams is the addition of wide-character streams. The effect on <iostream> is to add declarations for four more objects:
win wout werr wlogIf you want to control the standard streams as wide-character streams, you must use these objects instead of the traditional cin and friends. Note, however, that you cannot mix operations. Amendment 1 to the C Standard says that the first operation on a C stream, standard or otherwise, makes it either "narrow oriented" or "wide oriented." Operations of the other orientation subsequently fail.It takes some magic to make these objects wide oriented, but otherwise they are constructed much like their predecessors. The magic represents a major diversion, while the rest is just tedious repetition. So I continue to avoid the complications of showing these recent additions.
Using <iostream>
You include the header <iostream> to make use of any of the objects cin, cout, cerr, or clog. These objects let you read and write the standard streams available to any executing C++ program:
Insertions to cerr are flushed at the end of each inserter call, (The format flag ios: :unitbuf is set.) It is the preferred destination for debugging or error messages, lest the program crash before displaying useful output. Insertions to clog are more likely to be buffered. It is the preferred destination for "logging" high volumes of trace information, because insertions to it are less likely to degrade overall program performance.
- Extract from cin to read from the standard input stream.
- Insert to cout to write to the standard output stream.
- Insert to cerr to write to the standard error stream,
- Insert to clog to write to the standard error stream.
These objects are constructed before any constructor is called to initialize a static object. On rare occasions, as described above, you may need to be sure that cin and friends are initialized even earlier. In that case, be sure that program execution declares an object of class ios::lnit before the first expression that references any of these objects.
You can redirect any of these streams by suppling a replacement pointer to streambuf. For example, you can alter cin to extract from the named file "input" by writing:
#include <fstream> #include <iostream> ..... filebuf fb; fb.open("input", ios::in); cin.rdbuf(&fb);Do not redirect cerr this way, however, lest diagnostics go astray.
Implementing <iostream>
Listing 1 shows the file iostream, which implements the header <iostream>. It is one of those rare headers that is both short and overt. Given the general description of <iostream> above, you should not be surprised at anything you see here.Listing 2 shows the file iostream. c. Its primary business is to define the four objects declared in <iostream>. Its primary source of complexity is the need to double construct these and other objects, as I described earlier.
I first described the type _Uninitialized, and the value _Noinit, in conjunction with the header <ios>. (See the May 1994 installment, mentioned earlier.) A constructor that takes a single argument of type _Uninitialized is expected to perform no initialization. A declaration with the single argument value _Noinit calls this constructor. Along the way, I've shown several classes that have constructors of this sort ios, streambuf, istream, ostream, and filebuf. Here is where they all come into play.
Seven objects require double construction in this implementation. Four are the objects declared in <iostream>: cin, cout, cerr, and clog. Three more are objects of type filebuf that do not have external linkage: fin, fout, and ferr. All seven are constructed with placement new expressions in the constructor for ios::Init. This implementation of class filebuf accepts a constructor with a pointer to FILE parameter. That eliminates the need for yet another do-nothing constructor, for class stdiobuf.
The constructor for ios::Init never leaves the construction count ios::Init::_Init_cnt at zero. That way, the destructor can decrement the contraction count with no fear of future confusion. When it decrements the construction count to zero, the destructor knows to flush all three objects that control output streams. Bizarre patterns of constructor and destructor calls might cause the streams to be flushed more than once, but no reasonable pattern should ever cause the seven objects to be constructed more than once.
Testing <iostream>
Listing 3 shows the file tiostrea.c. It tests the basic properties of the objects declared in <iostream>. These are mostly cursory tests of the overt properties of the objects, without altering the streams they control until the very end. The program concludes by inserting into each of the three objects that control output streams. If all goes well, and if the standard error stream is directed to the same display as the standard output stream, the program prints:
Can write on streams: cout cerr clog SUCCESS testing <iostream>and takes a normal exit.This article is excerpted in part from P.J. Plauger, The Draft Standard C++ Library, (Englewood Cliffs, N.J.: Prentice-Hall, 1995).