例如:
#include<iostream>
using namespace std;
class A
{
public:
A(){cout<<k<<endl;}//make some output
static int k;
};
A a;//before `k`'s definition
int A::k=666;
int main()
{
}
答案是否肯定是666
(我已经在gcc8.1.0中对其进行了测试,答案是666
)或引起了不确定的行为?
此外,在此示例中,对象a
和定义A::k
在同一翻译单元中,如果它们在不同的单元中,将会发生什么情况,因为
不确定翻译单元中静态变量的初始化顺序
从我的角度来看,由于在同一个TU中初始化顺序是固定的,因此上面示例的答案应该不确定。
答案 0 :(得分:4)
如果要使构造函数成为非内联函数,可以,它将保证是您期望的值。
k
将受constant initialization(由于常量初始化程序的影响)的约束,而a
的初始化是动态的。所有静态初始化都在静态对象的动态初始化之前发生。但是即使k
是动态初始化的,也可以:
[basic.start.dynamic] (强调我的意思)
4是否动态初始化是实现定义的 具有静态存储持续时间的非本地非内联变量的值为 在main或main的第一个语句之前排序。 如果 推迟,它很可能在任何非初始化odr-use之前发生 相同中定义的任何非内联函数或非内联变量 转换单位作为要初始化的变量。它是 实现定义在哪个线程中以及在哪个位置 这样的延迟动态初始化程序。
并且非内联构造函数有资格使用此函数。这是Schwarz Counter技术的基础。
但是在您的示例中,c'tor是一个内联函数。因此,仅由于常量初始化而获得666。如果初始化程序不是常量表达式,则a
将根据同一TU中的声明顺序在k
之前进行动态初始化。
答案 1 :(得分:2)
是否在所有类对象之前初始化了静态数据成员?
取决于。具有静态存储持续时间的所有对象(包括所有静态数据成员)均在main
之前初始化。但是,如果您具有静态存储期限的类对象,则可以在静态数据成员之前初始化这些类对象。
答案肯定是666
是的
引起未定义的行为?
这里没有UB。
如果使用不同的单位会发生什么情况
静态成员的初始化是常量,而a
的构造函数在静态对象的动态初始化期间被调用。恒定初始化阶段在动态阶段之前。因此,在这种情况下,是否在不同的TU中声明它们并不重要。
答案 2 :(得分:0)
Static
成员将获得一个单独的房间。无论是否在创建类的对象之前对其进行初始化,都不会起作用。该程序将在没有undefined
行为的情况下运行。
例如,在C#中,如果未设置static
成员的值,则编译器会为其提供0
值。
static
成员的值
课将其设置为666
后,由该类A
组成的其他对象将获得其值为666