问题
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... ?
回答1:
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.
来源:https://stackoverflow.com/questions/14909173/how-does-the-scheme-below-garantees-therell-be-just-one-definition-for-the-obje