C ++ 20标准草案的[basic.scope.pdecl] / 1在注释中具有以下(非规范性)示例(合并请求3580之前的部分引号,请参见此问题的答案):
unsigned char x = x;
x使用其自己的(不确定的)值初始化。
这实际上在C ++ 20中具有明确定义的行为吗?
通常T x = x;
,由于在初始化完成之前x
的值是不确定的,因此表单的自我初始化具有未定义的行为。评估不确定值通常会导致未定义的行为([basic.indent] / 2),但是[basic.indent] /2.3中有一个特定的例外,该例外允许直接unsigned char
从unsigned char
具有不确定值的左值初始化变量(导致使用不确定值进行初始化) )。
这本身并不会因此导致不确定的行为,但会为其他类型T
不属于无符号窄字符类型或std::byte
如int x = x;
。这些注意事项同样适用于C ++ 17及之前的版本,另请参见底部的链接问题。
但是,即使对于unsigned char x = x;
,当前草案的[basic.lifetime] / 7也表示:
类似地,使用不依赖于其值的glvalue的属性,在其生命周期开始之前已得到明确定义。该程序在以下情况下具有未定义的行为:
glvalue用于访问对象,或者
[...]
这似乎暗示x
示例中的值只能在其生命周期内使用。
[...]
类型为T的对象的生存期始于以下情况:
- [...]和
- 它的初始化(如果有的话)已经完成(包括真空初始化)([dcl.init]),
[...]
因此,x
仅在初始化完成后才开始生命周期。但是在引用的示例中,x
在x
初始化完成之前使用的值。因此,使用具有未定义的行为。
我的分析是否正确,如果正确,是否会影响类似初始化前使用的情况,例如
int x = (x = 1);
据我所知,哪一个在C ++ 17及之前的版本中定义良好?
请注意,在C ++ 17(最终草案)中,开始存在生命周期的第二个要求是不同的:
- 如果对象具有非空初始化,则其初始化完成,
由于按照x
C ++ 17的定义(但不是当前草案中的定义)进行虚假的初始化,因此,在上述示例中的初始化程序中对其进行访问时,它的生存期已经开始,因此在两个示例中都没有未定义的行为由于x
C ++ 17中的生命周期。
C ++ 17之前的措词再次不同,但结果相同。
问题不在于使用不确定值时的不确定行为,例如以下问题中涉及到:
int x ^= x;
的语法格式不正确。您可以使用初始值设定项定义变量定义(即int x = x;
,虽然它是UB),也可以使用xor赋值表达式语句(即x ^= x;
,如果x
类型是int
,则它是UB ,是默认初始化的,而不是预先分配的)。您不能将这两者混为一谈。