在 C++ 中,内置类型的简单初始化是否不受静态初始化顺序失败的影响?
In C++ are simple initializations of built-in type immune to the static initialization order fiasco?
我知道 C++ 中的 static initialization order fiasco 和
construct 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.hpp
、foo.cpp
和 main.cpp
。)
但是,作为内置类型或它们的数组的变量呢?
因此,c
、d
、e
和 f
的全局赋值在此代码中安全吗?
链接器似乎可以为这些变量设置内存
所以不需要在 运行 时间进行初始化。但我能依靠吗
这个?
我知道我不应该使用全局变量。然而我是作者
库(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.
您的 c
、d
、e
和 f
对象具有常量初始化器,因此它们的初始化在静态初始化阶段完成(即使 c
和 d
本身不是常量),并且它们的值在所有动态初始化期间都是可用的,即使是那些之前词法出现的值。
我知道 C++ 中的 static initialization order fiasco 和
construct 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.hpp
、foo.cpp
和 main.cpp
。)
但是,作为内置类型或它们的数组的变量呢?
因此,c
、d
、e
和 f
的全局赋值在此代码中安全吗?
链接器似乎可以为这些变量设置内存
所以不需要在 运行 时间进行初始化。但我能依靠吗
这个?
我知道我不应该使用全局变量。然而我是作者 库(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 invokeconstexpr
constructors foro
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.
您的 c
、d
、e
和 f
对象具有常量初始化器,因此它们的初始化在静态初始化阶段完成(即使 c
和 d
本身不是常量),并且它们的值在所有动态初始化期间都是可用的,即使是那些之前词法出现的值。