1

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

2 回答 2

1

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

std::cout << stuff;

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

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

于 2019-07-20T08:39:22.853 回答
0

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

如何?

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

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

于 2019-07-20T08:40:57.547 回答