类中静态杆件的构造顺序

construction order of static member in class

本文关键字:顺序 静态      更新时间:2023-10-16
#include <iostream>
using namespace std;
class A
{
    int x;
public:
    A() { cout << "A's constructor called " << endl;  }
};
class B
{
    static A a;
public:
    B() { cout << "B's constructor called " << endl; }
    static A getA() { return a; }
};
A B::a;
int main()
{
        cout<<"Hin";
    B b1;
    B b2;
    return 0;
}

在这个程序中,我希望输出是

Hi
A's constructor called
B's constructor called
B's constructor called

但输出是

A's constructor called
Hi
B's constructor called
B's constructor called

您看到的行为是正确的,因为main()B::a都位于同一个翻译单元中。从标准中,撇开线程本地初始化的内容,您会看到具有静态存储持续时间的对象动态初始化。该标准确实有如何/何时初始化具有静态存储持续时间的对象的规则:

C++ § 3.6.2 [基本开始]

  1. 具有静态存储持续时间 (3.7.1( 或线程存储持续时间 (3.7.2( 的变量应在进行任何其他初始化之前初始化 (8.5(。

还有更多处理constexpr声明,但这不适用于您的代码。所以我们至少知道对象B::a的内存背景已经初始化为零,但是在这种情况下,构造函数何时真正触发?这称为动态初始化,根据标准:

C++ § 3.6.2 [基本开始]

    具有
  1. 静态存储持续时间的非局部变量的动态初始化是否在 main 的第一条语句之前完成,这是实现定义的。如果初始化推迟到main的第一个语句之后的某个时间点,则应在与要初始化的变量相同的翻译单元中定义的任何函数或变量的第一次odr-use(3.2(之前发生。

在您的情况下,根据情况main()B::a位于同一翻译单元中,为了保持标准,虽然main()可以在静态存储对象初始化之前开始执行,但main()本身驻留在翻译单元中,因此所有需要动态初始化的静态存储对象都必须在main()开始执行之前main()在同一单元中执行此操作。因此B::a是在main()的第一个语句之前构造的。

你为什么要关心?好吧,B::a总是可以驻留在main()不同的翻译单元中(例如:b.cpp(,并且您的结果可能不同,但仍然符合标准。此时,B::a是否在开始执行之前动态初始化main()同样必须在使用 odr b.cpp翻译单元中的任何函数或变量之前进行初始化。