我预计以下代码会产生分段错误(或其他UB):
struct T {
T();
};
T t;
char const* str = "Test string";
T::T() {
std::cout << str; // zero-initialised, only!
}
int main() {}
那是因为t
在str
之前被初始化了。由于零初始化,我希望str
保持值(char const*)0
。我对[C++11: 3.6.2/2]
的解释支持了这一点。
然而,the above snippet appears to output the string as expected(我也通过打印指针的值来确认行为)。
我是否缺少一些静态初始化规则,允许str
在t
开始构建之前进行值初始化?它在标准中的哪个位置?
这出现在static variable resolution at build time上,其中一个回答者声称使用char const*
而不是std::string
来获取静态全局可以避免静态初始化顺序失败。我不同意,但现在我不太确定......
答案 0 :(得分:6)
str
由常量表达式初始化,const char *
是POD类型(C ++ 03术语,但C ++ 11它是类似的,但具有不同的术语和方式更多允许的情况) 。这样的初始化在静态初始化阶段完成,静态初始化阶段没有顺序问题。它发生在任何动态初始化之前。 {em}动态初始化阶段初始化t
。
答案 1 :(得分:1)
在正常意义上,内置类型根本没有初始化。通常,它们的初始内容直接从二进制文件的特殊区域进行内存映射,作为加载它的一部分。
答案 2 :(得分:1)
我想我找到了;这里发生的事情不是关于内置类型,而是关于常量初始化器:
[C++11: 3.6.2/2]:
具有静态存储持续时间(3.7.1)或线程存储持续时间(3.7.2)的变量在进行任何其他初始化之前应进行零初始化(8.5)。执行常量初始化:
- 如果在具有静态或线程存储持续时间的引用的初始值设定项中出现的每个完整表达式(包括隐式转换)是常量表达式(5.19)并且引用绑定到左值指定具有静态存储持续时间的对象或临时对象(见12.2);
- 如果具有静态或线程存储持续时间的对象由构造函数调用初始化,如果构造函数是
constexpr
构造函数,如果所有构造函数参数都是常量表达式(包括转换),并且在函数调用替换之后(7.1.5),每个构造函数调用和完整表达式 mem-initializers 和 brace-or-equal-initializers 中的非静态数据成员是一个常量表达式;- 如果构造函数调用未初始化具有静态或线程存储持续时间的对象,并且其初始化程序中出现的每个完整表达式都是常量表达式。 < / LI>
零初始化和常量初始化一起称为静态初始化;所有其他初始化是动态初始化。在进行任何动态初始化之前,应执行静态初始化。 [..]
最后的句子似乎会覆盖后续的排序规则,使这种排序适用于翻译单位。
答案 3 :(得分:0)
char const* str = "Test string";
由编译器/链接器完成,因此它在程序开始运行之前就处于“初始化状态”。