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

Posted

技术标签:

【中文标题】在自己的初始化程序中使用变量【英文标题】:Use of variable in own initializer 【发布时间】:2020-04-13 23:41:05 【问题描述】:

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

unsigned char x = x;

[...] x 用它自己的(不确定的)值初始化。

这在 C++20 中真的有明确定义的行为吗?


由于x 的值在初始化完成之前不确定,通常T 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 用于访问对象,或

[...]

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

[basic.lifetime]/1 说:

[...]

类型 T 的对象的生命周期开始于:

[...] 和 其初始化(如果有)已完成(包括空初始化)([dcl.init]),

[...]

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

我的分析是否正确,如果正确,是否会影响类似的 use-before-initialization 案例,例如

int x = (x = 1);

据我所知,哪些在 C++17 及之前的版本中也得到了很好的定义?


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

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

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

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


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

Has C++ standard changed with respect to the use of indeterminate values and undefined behavior in C++14? Does initialization entail lvalue-to-rvalue conversion? Is int x = x; UB?

【问题讨论】:

@LanguageLawyer 我不确定我是否正确,尤其是在没有人回答的情况下。如果其他人在这里同意我的观点,我可能会稍后提交一份(或者其他人会在我之前提交),但我不想提交我不确定的问题。 @LanguageLawyer:如果工作文件明确地说错了,这不可能是编辑问题。 字被P1358改了。 @xskxzr 对,同时LanguageLawyer 也提交了editorial issue,似乎已转发给CWG 以澄清意图。 @clockw0rk int x ^= x; 的语法格式不正确。您可以使用初始化程序定义变量(即int x = x;,尽管它是UB)或xor 赋值表达式语句(即x ^= x;,尽管如果xint 类型,则它是UB,是默认值-已初始化且未事先分配)。您不能将这两者合二为一。 【参考方案1】:

这是作为editorial issue 打开的。它被转发给 CWG 进行(内部)讨论。大约 24 小时后,转发问题的人created a pull request 修改了示例以明确这是 UB:

这里,第二个 \tcodex 的初始化具有未定义的行为,因为初始化程序在其生命周期\irefbasic.life 之外访问第二个 \tcodex。

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

【讨论】:

以上是关于在自己的初始化程序中使用变量的主要内容,如果未能解决你的问题,请参考以下文章

在自己的初始值中使用的变量 Swift 3

在 Swift 5 中在其自己的初始值中使用的变量

Swift 错误:在其自己的初始值中使用的变量

JAVA面向对象程序设计(第二版) 袁绍欣 第六章答案

java中变量的作用域

linux上的core文件,麻烦牛人们帮忙解释下是啥原因