In-class 从相同类型的静态成员初始化
In-class initialization from static member of the same type
下面的代码是否有效,例如不会带来未定义的行为?
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
}
据我所知,所有具有静态存储持续时间的变量都是零初始化的。因此 s.i
在 S::s
创建时是 0
,一切都很好。但也许我遗漏了什么。
你错过了一些东西。具有静态存储持续时间的变量被归零,然后它们的构造函数被调用。
我不太清楚的是 S.i
的值 S.i
的初始化是否是未定义的行为(因为此时 S.i
未初始化) (因为它必须为零)。
编辑:Defect Report 2026 中的代码在效果上与此非常相似,并且被声明为格式错误(这意味着编译器肯定会出错)。我怀疑委员会的意图是 OP 的代码是未定义的行为。
编辑 2:以上 DR 指的是 constexpr
值。这可能足以改变无关紧要的事情。
话虽如此:如果您依靠非常仔细地阅读标准来使您的代码合法,那么您就是依靠编译器作者仔细阅读它。你可能是对的,但如果编译器作者误读并实现了其他东西(尽管希望他们最终会修复错误),这在短期内无济于事。
我认为它的定义很明确。
Static data members are initialized and destroyed exactly like
non-local variables.
[basic.start.static]/2 (emphasis mine)
A constant initializer for a variable or temporary object o is an
initializer whose full-expression is a constant expression, except
that if o is an object, such an initializer may also invoke constexpr
constructors for o and its subobjects even if those objects are of
non-literal class types. [ Note: Such a class may have a non-trivial
destructor. — end note ] Constant initialization is performed if a
variable or temporary object with static or thread storage duration is
initialized by a constant initializer for the entity. If constant
initialization is not performed, a variable with static storage
duration or thread storage duration is zero-initialized. Together,
zero-initialization and constant initialization are called static
initialization; all other initialization is dynamic initialization.
All static initialization strongly happens before ([intro.races]) any dynamic initialization. [ Note: The dynamic initialization of
non-local variables is described in [basic.start.dynamic]; that of
local static variables is described in [stmt.dcl]. — end note ]
[dcl.init]/6 (emphasis mine)
To zero-initialize an object or reference of type T means:
- if T is a scalar type, the object is initialized to the value obtained by converting the integer literal 0 (zero) to T;
- if T is a (possibly cv-qualified) non-union class type, each non-static data member, each non-virtual base class subobject, and, if
the object is not a base class subobject, each virtual base class
subobject is zero-initialized and padding is initialized to zero bits;
- if T is a (possibly cv-qualified) union type, the object's first non-static named data member is zero-initialized and padding is
initialized to zero bits;
- if T is an array type, each element is zero-initialized;
- if T is a reference type, no initialization is performed.
因为int i = s.i;
意味着s.i
是动态初始化的,所以保证事先是零初始化。因此,当它稍后用于初始化自身时,它的值将不会不确定。预期为 0。
下面的代码是否有效,例如不会带来未定义的行为?
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
}
据我所知,所有具有静态存储持续时间的变量都是零初始化的。因此 s.i
在 S::s
创建时是 0
,一切都很好。但也许我遗漏了什么。
你错过了一些东西。具有静态存储持续时间的变量被归零,然后它们的构造函数被调用。
我不太清楚的是 S.i
的值 S.i
的初始化是否是未定义的行为(因为此时 S.i
未初始化) (因为它必须为零)。
编辑:Defect Report 2026 中的代码在效果上与此非常相似,并且被声明为格式错误(这意味着编译器肯定会出错)。我怀疑委员会的意图是 OP 的代码是未定义的行为。
编辑 2:以上 DR 指的是 constexpr
值。这可能足以改变无关紧要的事情。
话虽如此:如果您依靠非常仔细地阅读标准来使您的代码合法,那么您就是依靠编译器作者仔细阅读它。你可能是对的,但如果编译器作者误读并实现了其他东西(尽管希望他们最终会修复错误),这在短期内无济于事。
我认为它的定义很明确。
Static data members are initialized and destroyed exactly like non-local variables.
[basic.start.static]/2 (emphasis mine)
A constant initializer for a variable or temporary object o is an initializer whose full-expression is a constant expression, except that if o is an object, such an initializer may also invoke constexpr constructors for o and its subobjects even if those objects are of non-literal class types. [ Note: Such a class may have a non-trivial destructor. — end note ] Constant initialization is performed if a variable or temporary object with static or thread storage duration is initialized by a constant initializer for the entity. If constant initialization is not performed, a variable with static storage duration or thread storage duration is zero-initialized. Together, zero-initialization and constant initialization are called static initialization; all other initialization is dynamic initialization. All static initialization strongly happens before ([intro.races]) any dynamic initialization. [ Note: The dynamic initialization of non-local variables is described in [basic.start.dynamic]; that of local static variables is described in [stmt.dcl]. — end note ]
[dcl.init]/6 (emphasis mine)
To zero-initialize an object or reference of type T means:
- if T is a scalar type, the object is initialized to the value obtained by converting the integer literal 0 (zero) to T;
- if T is a (possibly cv-qualified) non-union class type, each non-static data member, each non-virtual base class subobject, and, if the object is not a base class subobject, each virtual base class subobject is zero-initialized and padding is initialized to zero bits;
- if T is a (possibly cv-qualified) union type, the object's first non-static named data member is zero-initialized and padding is initialized to zero bits;
- if T is an array type, each element is zero-initialized;
- if T is a reference type, no initialization is performed.
因为int i = s.i;
意味着s.i
是动态初始化的,所以保证事先是零初始化。因此,当它稍后用于初始化自身时,它的值将不会不确定。预期为 0。