静态数据成员是否在所有类对象之前初始化?

Are static data members initialized before all class objects?

本文关键字:对象 初始化 数据成员 是否 静态      更新时间:2023-10-16

例如:

#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 中初始化顺序是固定的,所以上面示例的答案应该是无限的。

如果要使构造函数成为非内联函数,是的,它将保证是您期望的值。

k将受到常量初始化(由于常量初始值设定项),而a的初始化是动态的。所有静态初始化都发生在静态对象的动态初始化之前。但即使k动态初始化的:

[basic.start.dynamic](强调我的)

4 是否动态初始化是实现定义的 具有静态存储持续时间的非局部非内联变量为 在 Main 或 的第一个语句之前排序,或被推迟。如果它 被推迟,它强烈发生在任何非初始化 ODR 使用之前 同一中定义的任何非内联函数或非内联变量 翻译单元作为要初始化的变量。是的 实现定义在哪些线程中以及在哪些点 程序发生这种延迟的动态初始化。

非内联构造函数有资格使用此类函数。这是施瓦茨计数器技术的基础。

但是在您的示例中,c'tor 是一个内联函数。因此,只有由于不断初始化,您才能获得 666。如果初始值设定项不是常量表达式,则a将在同一 TU 中根据声明顺序进行动态初始化,然后再进行k

静态数据成员是否在所有类对象之前初始化?

取决于。所有具有静态存储持续时间的对象(包括所有静态数据成员)都在main之前初始化。但是,如果您有具有静态存储持续时间的类对象,则这些类对象可能会在静态数据成员之前初始化。

答案保证是666

是的。

导致未定义的行为?

这里没有UB。

如果他们在不同的单位会发生什么

静态成员的初始化是恒定的,而a的构造函数在静态对象的动态初始化期间调用。常量初始化阶段在动态阶段之前。因此,在这种情况下,它们是否在不同的 TU 中声明并不重要。

Static

成员将获得一个单独的房间。无论是否在类创建对象之前初始化它,都不会有任何影响。程序将在没有undefined行为的情况下运行。

例如,在 C# 中,如果未设置static成员的值,则编译器将为其提供0值。

  • 您可以在对象创建后获取/设置static成员的值 .class
  • 正如您已经知道的那样,您也可以在之前设置。

将其设置为666后,由该类A组成的其他对象将获得其值666