4

Here you'll find the following statements under Which header ? :

Finally, <iostream> provides the eight standard global objects (cin, cout, etc). To do this correctly, this header also provides the contents of the <istream> and <ostream> headers, but nothing else. The contents of this header look like

#include <ostream>
#include <istream>

namespace std
{
    extern istream cin;
    extern ostream cout;
    ....

    // this is explained below
    static ios_base::Init __foo;    // not its real name
}

Now, the runtime penalty mentioned previously: the global objects must be initialized before any of your own code uses them; this is guaranteed by the standard. Like any other global object, they must be initialized once and only once. This is typically done with a construct like the one above, and the nested class ios_base::Init is specified in the standard for just this reason.

How does it work? Because the header is included before any of your code, the __foo object is constructed before any of your objects. (Global objects are built in the order in which they are declared, and destroyed in reverse order.) The first time the constructor runs, the eight stream objects are set up.

My question: when I include the header file <iostream> in several .cpp files, how does the scheme above guarantees that there will be just one definition for the objects cin, cout, etc... ?

John Kalane
  • 1,163
  • 8
  • 17
  • The "one definition" isn't interesting - that's just part of the (compiled) standard library. What's interesting is the "one initialization". (I think the technique is called ["Schwartz counter"](http://stackoverflow.com/q/9251763/596781).) – Kerrek SB Feb 16 '13 at 10:20
  • 2
    AFAIK, the `cout`, `cin` et al. objects are just declared as `extern` in the header, the actual definitions are inside the standard lib's files. Now, `ios_base::Init` is declared `static`, thus each translation unit has its own copy. The constructors/destructors of `Init` object do some kind of reference counting to know when to initialize/destroy standard stream objects. At least that's how [stdlibc++ seems to do it](http://gcc.gnu.org/viewcvs/trunk/libstdc%2B%2B-v3/include/std/iostream?view=markup). – jrok Feb 16 '13 at 10:27
  • @jrok Everything you said is clear to me. What I don't understand is how `ios_base::Init` will avoid multiple definitions of the global objects cin, cout, ..., when `` is included in several `.cpp` files. – John Kalane Feb 16 '13 at 10:35
  • 4
    Like I said, they're not defined in ``, they're just *declared*. – jrok Feb 16 '13 at 10:36
  • @jrok I'll rephrase my question: how will the scheme above garantee that there will be just one definition for the global objects cin, cout, ... ? – John Kalane Feb 16 '13 at 10:39
  • The "how" depends on your compiler's implementation, I believe. If you're using gcc, I'd start looking [here](http://gcc.gnu.org/viewcvs/trunk/libstdc%2B%2B-v3/src/c%2B%2B98/ios_init.cc?view=markup). – jrok Feb 16 '13 at 10:51

1 Answers1

3

It doesn't really guarantee that. The one definition problem is solved by simply defining the stream objects once in a .cpp file which is part of the library. The code in the question just contains the declaration of the standard streams.

What is does guarantee is that the objects will be initialized before being used. One problem with global objects in C++ is that while they are initialized in order within each .cpp file, we don't know the order the linker will put objects from separate files. This might cause problems if one object tries to use another object before that one gets initialized, and we don't know the exact order - see Static initialization order fiasco.

One workaround, as used here, is to put an Init object in the header declaring the stream objects. Because you have to include the header before using the stream, we know that this Init object will be at the top of the file, and therefore constructed before other objects that might use the streams.

Now, the constructor of the Init class is responsible for the initialization of the stream objects. This has to be done early, and only once. Exactly how is left up to each implementation, but the code hints at using a counter keeping track of the number of Init objects created (and presumably treating the first specially).

This is just one way of doing this, using only the standard language. Some implementations have other tricks, like #pragmas or an init_priority directive to convince the linker to put library code before user code. In that case it just works by magic, without using an Init class.

Community
  • 1
  • 1
Bo Persson
  • 90,663
  • 31
  • 146
  • 203
  • `What is does guarantee is that the objects will be initialized before being used. One problem with global objects in C++ is that while they are initialized in order within each .cpp file, we don't know the order the linker will put objects from separate files. This might cause problems if one object tries to use another object before that one gets initialized, and we don't know the exact order .` As far as I can understand this problem has already been solved in C++11, at least according to this answer http://stackoverflow.com/a/8785008/1042389. – John Kalane Feb 16 '13 at 14:12
  • The only difference is that in C++11 is says that the implementation should behave as-if an `Init` object is constructed. That's the way it worked in C++03 as well, it just wasn't spelled out (because it was assumed to be obvious :-). See [Library Defect Report #369](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#369) – Bo Persson Feb 16 '13 at 15:14
  • `The one definition problem is solved by simply defining the stream objects once in a .cpp file which is part of the library.` Do you have any reference to support this ? Does the standard say anything about this ? – John Kalane Feb 16 '13 at 15:26