在自己的初始值设定项中使用变量

Use of variable in own initializer

本文关键字:变量 自己的      更新时间:2023-10-16

[basic.scope.pdecl]/1 的 C++20 标准草案在注释中有以下(非规范(示例(部分引用了 pull request 3580 合并之前的内容,请参阅对此问题的回答(:

unsigned char x = x;

[...] x 使用其自己的(不确定(值进行初始化。

这实际上在 C++20 中具有明确定义的行为吗?


通常,表单T x = x;的自初始化具有未定义的行为,因为x的值在初始化完成之前是不确定的。计算不确定值通常会导致未定义的行为 ([basic.indent]/2(,但 [basic.indent]/2.3 中有一个特定的例外,它允许从具有不确定值的左值unsigned char直接初始化unsigned char变量(导致使用不确定值初始化(。

因此,仅此一项不会导致未定义的行为,但对于不是无符号窄字符类型或std::byte的其他类型的T,例如int x = x;.这些注意事项也适用于 C++17 及之前的内容,另请参阅底部的链接问题。

然而,即使是unsigned char x = x;,当前草案的[basic.life]/7说:

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

  • GL值用于访问对象,或

  • [...]

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

[基本寿命]/1 说:

[...]

T 类型的对象的生存期在以下情况下开始:

  • [...]和
  • 它的初始化(如果有的话(是完整的(包括空初始化(([dcl.init](,

[...]

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

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

int x = (x = 1);

据我所知,在 C++17 及之前也有明确的定义?


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

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

由于x将按照 C++17 的定义进行空洞初始化(但不是当前草案中的定义(,因此在上面给出的示例中,当在初始值设定项中访问它时,它的生命周期就已经开始了,因此在这两个示例中,由于 C++17 中的x生命周期,没有未定义的行为。

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


问题不在于使用不确定值时的未定义行为,例如以下问题涵盖了这些行为:

  • C++ C++14 中使用不确定值和未定义行为的标准是否发生了变化?
  • 初始化是否需要左值到右值的转换?int x = x;是 UB 吗?

这是作为编辑问题打开的。它被转发给CWG进行(内部(讨论。大约 24 小时后,转发问题的人创建了一个拉取请求,该请求修改了示例以明确这是 UB:

在这里,第二个 \tcode{x}

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

此后添加了该 PR 并关闭了该问题。因此,很明显,明显的解释(由于访问其生存期尚未开始的对象而导致的 UB(是预期的解释。委员会似乎打算使这些结构不起作用,并且该标准的非规范性文本已经更新以反映这一点。