关于std :: cout,为什么要使用“ extern”而不是“ singleton pattern”

时间:2019-07-20 08:22:01

标签: c++ iostream effective-c++

我阅读了第04项提到的有效的C ++

  

通过用本地静态对象替换非本地静态对象,避免跨翻译单元的初始化顺序问题。

我认为“全局且只有一个对象”应该是单例模式,而不是在阅读了此项目之后的外部对象。

例如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;
  

在不同翻译单元中定义的非局部静态对象的初始化相对顺序不确定。

因此,当我调用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;
}

2 个答案:

答案 0 :(得分:0)

使用extern变量可以使(主观上)更好的语法

std::cout << stuff;

强调标准流是唯一的对象,而不是某些函数调用的结果。由于流是要在流对象中完成的,因此使用对象符号可以更好地将其绑定到其中。

对于静态初始化顺序失败,标准库通过使用Schwarz Counter技术进行初始化来避免它。初始化按定义良好的顺序进行,因为包含iostream向包含的TU添加了类型为Init的特殊全局对象。该对象的构造函数会在首次使用流之前处理流的初始化,无论该第一次使用在哪里。

答案 1 :(得分:0)

因为C ++选择了一种更为复杂的方法,因此可以提高直接对象访问的效率和简便性,并且仍然避免了静态初始化顺序的惨败。

如何?

c ++标准流实际上不是静态初始化的。相反,#include-ing <iostream>定义了类型为std::ios_base::Init的全局静态对象,该对象管理全局引用计数,并由此管理C ++流。

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