从同一类型的静态成员进行类内初始化

αλε*_*λυτ 6 c++ initialization static-members language-lawyer in-class-initialization

以下代码是否有效,例如是否带来未定义的行为?

struct S
{
    int i = s.i;
    static S s;
};

S S::s;

int main()
{
    S a;  // a.i = 0
    S::s.i = 42;
    S b;  // b.i = 42
}
Run Code Online (Sandbox Code Playgroud)

据我所知,所有具有静态存储持续时间的变量都是零初始化.因此s.i0S::s创造,一切都是好的.但也许我错过了一些东西.

Sto*_*ica 6

我认为它的定义很明确.

[class.static.data]/6

静态数据成员的初始化和销毁​​与非局部变量完全相同.

[basic.start.static]/2(强调我的)

变量或临时对象的常量初始化器o是一个初始化器,其full-expression是一个常量表达式,除非o是一个对象,这样的初始化器也可以调用o及其子对象的constexpr构造函数,即使这些对象是非对象的-literal类类型.[注意:这样的类可能有一个非平凡的析构函数. - 结束注释]如果具有静态或线程存储持续时间的变量或临时对象由实体的常量初始化程序初始化,则执行常量初始化.如果未执行常量初始化,则具有静态存储持续时间或线程存储持续时间的变量为零初始化.零初始化和常量初始化一起称为静态初始化; 所有其他初始化是动态初始化.所有静态初始化都强烈地发生在([intro.races])任何动态初始化之前.[注意:非局部变量的动态初始化在[basic.start.dynamic]中描述; 本地静态变量的描述在[stmt.dcl]中描述. - 结束说明]

[dcl.init]/6(强调我的)

零初始化T类型的对象或引用意味着:

  • 如果T是标量类型,则将对象初始化为通过将整数0(零)转换为T而获得的值;
  • 如果T是(可能是cv限定的)非联合类类型,每个非静态数据成员,每个非虚基类子对象,如果对象不是基类子对象,则每个虚基类子对象为零-initialized和padding初始化为零位;
  • 如果T是(可能是cv限定的)联合类型,则对象的第一个非静态命名数据成员被零初始化,并且填充被初始化为零位;
  • 如果T是数组类型,则每个元素都是零初始化的;
  • 如果T是引用类型,则不执行初始化.

因为int i = s.i;均值s.i通过动态初始化,所以保证事先将其初始化为零.因此,当它稍后用于初始化时,它的价值将不会是不确定的.预计为0.