#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<<"Hi\n";
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
答案 0 :(得分:2)
您看到的行为是正确的,因为main()
和B::a
都位于同一个翻译单元中。从标准中,省略了线程本地初始化的东西,您将看到静态存储持续时间的对象的动态初始化。该标准确实具有如何/何时初始化具有静态存储持续时间的对象的规则:
C ++§3.6.2[basic.start.init]
- 具有静态存储持续时间(3.7.1)或线程存储持续时间(3.7.2)的变量在进行任何其他初始化之前应进行零初始化(8.5)。
醇>
还有更多涉及constexpr
声明的处理,但这不适用于您的代码。所以我们至少知道对象B::a
的内存背景已被零初始化,很好,但是在这种情况下构造函数何时实际触发?这称为动态初始化,并根据标准:
C ++§3.6.2[basic.start.init]
- 实现定义是否在
醇>main
的第一个语句之前完成具有静态存储持续时间的非局部变量的动态初始化。如果初始化延迟到第一个main语句之后的某个时间点,它应该在与要初始化的变量相同的转换单元中定义的任何函数或变量的第一个odr-use(3.2)之前发生。
在您的情况下,根据情况,main()
与B::a
位于同一翻译单元中,在保持标准时,main()
可能会在之前开始执行 / em>静态存储对象已初始化,main()
本身驻留在翻译单元中,因此需要在与main()
相同的单元中进行动态初始化的所有静态存储对象必须这样做< / strong> main()
开始执行之前。因此B::a
是在main()
的第一个语句之前构建的。
你为什么要关心?好吧,B::a
可以始终驻留在与<{1}}不同的翻译单元中(例如main()
),您的结果可能会有所不同,但仍符合标准。此时,它是实现定义的b.cpp
是否会在B::a
开始执行之前动态初始化,但同样,必须在{{1}中的任何函数或变量之前初始化翻译单位是使用过的。