在 C++ 中,内置类型的简单初始化是否不受静态初始化顺序失败的影响?

In C++ are simple initializations of built-in type immune to the static initialization order fiasco?

我知道 C++ 中的 static initialization order fiascoconstruct on first use idiom 避免它。因此在下面的代码中 a 的全局分配可能发生在 foo::a 之前,所以 a 的值未定义。另一方面,全球 b 的赋值是可以的,因为它调用了函数 foo::b().

#include <iostream>
#include <string>

using namespace std;

// foo.hpp

class foo {
public:
  static const string a;
  static const string& b();
  static const char* const c;
  static const char* const d[2];
  static const int e;
  static const int f[2];
};

// foo.cpp

const string foo::a("astr");
const string& foo::b() {
  static const string t("bstr");
  return t;
}
const char* const foo::c = "cstr";
const char* const foo::d[2] = {"dstr1", "dstr2"};
const int foo::e = 5;
const int foo::f[2] = {6, 7};

// main.cpp

// global initializations
string a = foo::a;              // dangerous, might be "" or "astr"
string b = foo::b();            // safe, guaranteed to be "bstr"
const char* c = foo::c;         // what about these...?
const char* d = foo::d[0];
int e = foo::e;
int f = foo::f[0];

int main() {
  cout << a << " " << b << "\n"
       << c << " " << d << "\n"
       << e << " " << f << "\n";
}

(假设我在这里合并了 foo.hppfoo.cppmain.cpp。) 但是,作为内置类型或它们的数组的变量呢? 因此,cdef 的全局赋值在此代码中安全吗? 链接器似乎可以为这些变量设置内存 所以不需要在 运行 时间进行初始化。但我能依靠吗 这个?

我知道我不应该使用全局变量。然而我是作者 库(foo.cpp 和 foo.hpp),我无法控制 我图书馆的用户(main.cpp 的作者)有。

这里的关键是“static 初始化”(使用标准语言正式称为具有静态存储持续时间 的对象的动态初始化)之间的区别排序失败)和静态初始化.

标准说(第 [basic.start.static] 节)

A constant initializer for an object o is an expression that is a constant expression, except that it may also invoke constexpr constructors for o and its subobjects even if those objects are of non-literal class types. [ Note: Such a class may have a non-trivial destructor — end note ]

Constant initialization is performed:

  • if each full-expression (including implicit conversions) that appears in the initializer of a reference with static or thread storage duration is a constant expression and the reference is bound to a glvalue designating an object with static storage duration, to a temporary object or subobject thereof, or to a function;
  • if an object with static or thread storage duration is initialized by a constructor call, and if the initialization full-expression is a constant initializer for the object;
  • if an object with static or thread storage duration is not initialized by a constructor call and if either the object is value-initialized or every full-expression that appears in its initializer is a constant expression.

If constant initialization is not performed, a variable with static storage duration or thread storage duration is zero-initialized. Together, zero-initialization and constant initialization are called static initialization; all other initialization is dynamic initialization. Static initialization shall be performed before any dynamic initialization takes place.

您的 cdef 对象具有常量初始化器,因此它们的初始化在静态初始化阶段完成(即使 cd 本身不是常量),并且它们的值在所有动态初始化期间都是可用的,即使是那些之前词法出现的值。