关于std::cout,为什么用"extern"而不是"singleton pattern"

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

我阅读了 effective C++ 项目 04 提到的

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

看完这篇我觉得"global and only-one object"应该是单例模式,而不是extern object

例如I/O对象(std::cout)

但是std::cout似乎是外部对象。 (http://www.cplusplus.com/reference/iostream/cout/)

我对此很困惑。

编辑:添加代码

我从这本书中获取了一些代码。

首先是错误的代码:

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.

所以上面的代码在我调用tfs时可能是错误的。

因为tfs可能没有完成初始化

推荐代码:

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;
}

使用 extern 变量允许

的(主观上)更好的语法
std::cout << stuff;

强调标准流是一个独特的对象,而不是某些函数调用的结果。由于流式传输是要在流对象中完成的,因此使用对象表示法可以更好地融入其中。

至于静态初始化顺序的失败,标准库通过对包括 TU 使用 Schwarz Counter technique for initialization. Initialization happens in a well defined order because including iostream adds a special global object of type Init 来避免它。对象的构造函数在首次使用之前处理流的初始化,无论首次使用是在何处。

因为 C++ 选择了一种更精细的方法,获得了直接对象访问的效率和简单性,同时仍然避免了静态初始化顺序的失败。

如何?

C++ 标准流实际上并不是静态初始化的。相反,#include-ing <iostream> defines a global static object of type std::ios_base::Init 管理全局 reference-count,并用它来初始化 C++ 流。

或者至少,它是这样指定的,但总有 as-if rule