为什么我可以在一个文件中按顺序初始化两个静态类变量而不是三个?

Lu*_*ian 8 c++

我正在使用静态类变量,我碰到了一些我不明白的意外情况.

Stroustrup的书TC++ PL4在15.4.1非局部变量的初始化中说,"在不同的翻译单元中没有保证全局变量初始化的顺序." 但是看到多个翻译单元; 我没有测试文件之间的依赖关系,这是在一个文件中.同一部分说"原则上,在main()调用之前初始化在任何函数外部定义的变量(即全局,名称空间和类静态变量).翻译单元中的这些非局部变量按其定义顺序初始化.

如果我在文件的顶部设置它:

class Test1 {
public:
static double test1;
};

class Test2 {
public:
static double test2;
};

class Test3 {
public:
static double test3;
};
Run Code Online (Sandbox Code Playgroud)

我可以做这个:

double Test2::test2 = Test1::test1;
double Test1::test1 = 1.125;
Run Code Online (Sandbox Code Playgroud)

并将此语句放在main中以检查值:

cout << Test1::test1 << " " << Test2::test2;
Run Code Online (Sandbox Code Playgroud)

两个值都是1.125.我知道这两个变量都在这个范围内定义,但是如果它们按定义顺序初始化,那么上面的语句如何使用下面语句中的数据呢?此外,顶部的类定义顺序在任何这些情况下都不会改变.

如果我使用这种安排:

double Test2::test2 = Test1::test1;
double Test3::test3 = Test2::test2;
double Test1::test1 = 1.125;
Run Code Online (Sandbox Code Playgroud)

它们也都是1.125.

但如果我这样做:

double Test3::test3 = Test2::test2;
double Test2::test2 = Test1::test1;
double Test1::test1 = 1.125;
Run Code Online (Sandbox Code Playgroud)

Test3::test3 将是0.

看起来它可以在一个层中寻找另一个定义,但如果该定义需要另一个定义,它就会停止并且只分配零.但我不知道到底发生了什么.

有谁知道为什么这样做?我在http://cpp.sh(GCC)的C++ '14模式和VSE 2012中尝试了这个,并且结果一致.

编辑:看,我一直看到你无法预测它,但这种观察似乎掩盖了一个明显的事实,即文件的不确定性与单个文件中的(可能不存在的?)不确定性之间存在差异.Stroustrup基本上说有区别,但静态变量很奇怪.

我曾经想过,即使在单个文件的情况下,类定义也可能在原始文件之外看起来初始化静态数据成员,因此就编译逻辑而言,文件循环再次找到自己,生成UB.如果编译器被编程为分配零而不是跳转到第三个外部变量,结果将是可预测且更稳定的,但我没有任何证据证明文件可以像这样在外部引用自身.

编辑2:这似乎是静态和动态初始化的问题,静态初始化在编译时分配零或给定常量,然后动态然后使用这些值(如Mark B所说),如下所示: 什么是对象的动态初始化C++? 但我还是要问,不管是不是UB.

最后编辑:不难找到信息,行为非常有根据而不是UB,请看这里:http: //en.cppreference.com/w/cpp/language/initialization

Mar*_*k B 5

所以这里发生的事情是初始化有两个阶段:静态和动态.编译器可以看到这test1是一个常量并将该常量嵌入到二进制中,默认为该值.它不能这样做test2test3,因此那些获得的值0在二进制.

然后在main启动之前,动态初始化阶段开始,将0值从test2进入test3,然后将1.25常量从test1进入test2.

所有这一切都说从不依赖于此,并始终以合理的顺序初始化您的变量.