简体   繁体   中英

About std::cout, why use “extern” rether than “singleton pattern”

I read effective C++ which item 04 mentioned

Avoid initialization order problems across translation units by re-placing non-local static objects with local static objects.

I think that "global and only-one object" should be singleton pattern, not extern object after I read this item.

such as I/O object(std::cout)

But std::cout seems extern object. ( http://www.cplusplus.com/reference/iostream/cout/ )

I am confused about this.

edit: add code

I Capture some code form this book.

First is bad code:

class FileSystem {
// from your library’s header file
public:
 ...std::size_t numDisks( ) const;
// one of many member functions...
}; 
extern FileSystem tfs;

the relative order of initialization of non-local staticobjects defined in different translation units is undefined.

So abovementioned code may be fault when I call tfs.

Because tfs may not complete initialization.

The recommand code:

class FileSystem { ... }; // as before
FileSystem& tfs()
{
  static FileSystem fs;
  return fs;
}
class Directory { ... };// as beforeDirectory::Directory( params )
Directory::Directory( params ) // as before, except references to tfs are 
                               //now to tfs( )
{
...
std::size_t disks = tfs().numDisks( );
...
}
Directory& tempDir()
{
  static Directory td(params);
  return td;
}

Using an extern variable allows the (subjectively) nicer syntax of

std::cout << stuff;

Emphasizing that the standard stream is a unique object and not the result of some function call. Since streaming is meant to be done into stream objects, using object notation ties better into it.

As for the static initialization order fiasco, the standard library avoids it by using the Schwarz Counter technique for initialization. Initialization happens in a well defined order because including iostream adds a special global object of type Init to the including TU. The object's constructor handles the initialization of the stream before its first use, wherever that first use may be.

Because C++ opted for a more elaborate approach, getting the efficiency and simplicity of direct object access and still avoiding the static initialization order fiasco.

How?

The c++ standard streams are not actually initialized statically. Instead, #include-ing <iostream> defines a global static object of type std::ios_base::Init , which manages a global reference-count, and with it the initialization of the C++ streams.

Or at least, that's how it is specified, but there is always the as-if rule .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM