在自己的初始化器中使用变量


22

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 charunsigned char具有不确定值的左值初始化变量(导致使用不确定值进行初始化) )。

这本身并不会因此导致不确定的行为,但会为其他类型T不属于无符号窄字符类型或std::byteint x = x;。这些注意事项同样适用于C ++ 17及之前的版本,另请参见底部的链接问题。

但是,即使对于unsigned char x = x;,当前草案的[basic.lifetime] / 7也表示:

类似地,使用不依赖于其值的glvalue的属性,在其生命周期开始之前已得到明确定义。该程序在以下情况下具有未定义的行为:

  • glvalue用于访问对象,或者

  • [...]

这似乎暗示x示例中的值只能在其生命周期内使用。

[basic.lifetime] / 1说:

[...]

类型为T的对象的生存期始于以下情况:

  • [...]和
  • 它的初始化(如果有的话)已经完成(包括真空初始化)([dcl.init]),

[...]

因此,x仅在初始化完成后才开始生命周期。但是在引用的示例中,xx初始化完成之前使用的值。因此,使用具有未定义的行为。

我的分析是否正确,如果正确,是否会影响类似初始化前使用的情况,例如

int x = (x = 1);

据我所知,哪一个在C ++ 17及之前的版本中定义良好?


请注意,在C ++ 17(最终草案)中,开始存在生命周期的第二个要求是不同的

  • 如果对象具有非空初始化,则其初始化完成,

由于按照xC ++ 17的定义(但不是当前草案中的定义)进行虚假的初始化,因此,在上述示例中的初始化程序中对其进行访问时,它的生存期已经开始,因此在两个示例中都没有未定义的行为由于xC ++ 17中的生命周期。

C ++ 17之前的措词再次不同,但结果相同。


问题不在于使用不确定值时的不确定行为,例如以下问题中涉及到:


@LanguageLawyer我不确定自己是正确的,尤其是如果没有人回答的话。如果其他人在这里同意我的意见,我可能会稍后提出(或者可能有人会在我之前提出),但是我不想提出我不确定的问题。
核桃

@LanguageLawyer:如果工作文件明确地说出了错误的话,那不是社论问题。
戴维斯·鲱鱼

1
该字由P1358更改。
xskxzr

1
@xskxzr对,同时,LanguageLawyer也提交了编辑问题,该问题似乎已转发给CWG以澄清其意图。
核桃

1
@ clockw0rk int x ^= x;的语法格式不正确。您可以使用初始值设定项定义变量定义(即int x = x;,虽然它是UB),也可以使用xor赋值表达式语句(即x ^= x;,如果x类型是int,则它是UB ,是默认初始化的,而不是预先分配的)。您不能将这两者混为一谈。
胡桃

Answers:


8

这是作为社论发行的。它已转发给CWG进行(内部)讨论。大约24小时后,转发问题的人创建了一个拉取请求,该请求修改了示例以使人清楚这是UB:

在这里,第二个\ tcode {x}的初始化具有未定义的行为,因为初始化程序在其生存期\ iref {basic.life}之外访问第二个\ tcode {x}。

此后添加了PR,此问题已解决。因此,显而易见的是,显而易见的解释(由于访问生命周期尚未开始的对象而导致的UB)是预期的解释。看来该委员会的目的使这些构造不起作用,并且该标准的非规范性文本已得到更新以反映这一点。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.