关于std::cout,为什么使用"extern"比"singleton pattern"

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

本文关键字:extern singleton pattern std cout 为什么 关于      更新时间:2023-10-16

我阅读了第 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;
}

使用 extern 变量允许(主观上(更好的语法

std::cout << stuff;

强调标准流是唯一对象,而不是某些函数调用的结果。由于流式处理旨在完成流对象,因此使用对象表示法可以更好地与流对象相关联。

至于静态初始化顺序惨败,标准库通过使用施瓦茨计数器技术进行初始化来避免它。初始化按明确定义的顺序进行,因为包含 iostream 会将类型为 Init 的特殊全局对象添加到包含 TU。对象的构造函数在流首次使用之前处理流的初始化,无论第一次使用在哪里。

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

如何?

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

或者至少,它是这样指定的,但总是有假设规则。