为什么即使存在此静态成员,也不会构造它?

Why is this static member not constructed even though it exists?

本文关键字:存在 静态成员 为什么      更新时间:2023-10-16

前几天我遇到了一些意想不到的行为,并将其简化为这几行代码。我在VC++ 19.0,Clang 3.8和GCC 5.4.0以及8.2.0上对其进行了测试。每种情况下的输出都只有1,而我原本期望它以Hello开头,以Goodbye完成。

#include <iostream>
template <class T> struct X { static T data; };
template <class T> T X<T>::data;
struct A
{
A()
{
std::cout << "Hello" << std::endl;
}
~A()
{
std::cout << "Goodbye" << std::endl;
}
};
struct B : X<A> { };
int main(int argc, char **argv)
{
std::cout << sizeof(B::data) << std::endl;
}

显然B::data存在,但从未调用其构造函数和析构函数。有趣的是,如果我将其添加到测试中

assert(typeid(B::data) == typeid(A));

GCC 的行为与我最初预期的那样,但 Clang 和 VC++ 的行为都像以前一样。所以我在这里的怀疑是,这种行为是不确定的,而不仅仅是出乎意料的。我对语言标准措辞不够熟悉,无法自己确切地说出在这种情况下的违规行为是什么。但它肯定违背了我对静态成员和继承如何工作的直觉。

根据 [temp.inst]/3:

。特别是,静态数据成员的初始化(以及任何关联的副作用(不会发生,除非静态数据成员本身的使用方式要求存在静态数据成员的定义。

和 [expr.context]/1:

[注意

:在未计算的操作数中,可以命名非静态类成员([expr.prim.id](,并且对象或函数的命名本身不需要提供定义([basic.def.odr](。

X<A>::data只用作sizeof的操作数,这是一个未求值的操作数,因此X<A>::data没有初始化。

对于typeid的情况,我认为这是一个GCC错误。

访问结构的静态成员不会实例化它,因此永远不会调用您情况下struct X<A>的构造函数。

您甚至可以简化代码以在没有模板的情况下尝试,因为它不会影响此处的结果。