在自己的初始化程序中使用变量
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? Isint x = x;
UB?
【问题讨论】:
@LanguageLawyer 我不确定我是否正确,尤其是在没有人回答的情况下。如果其他人在这里同意我的观点,我可能会稍后提交一份(或者其他人会在我之前提交),但我不想提交我不确定的问题。 @LanguageLawyer:如果工作文件明确地说错了,这不可能是编辑问题。 字被P1358改了。 @xskxzr 对,同时LanguageLawyer 也提交了editorial issue,似乎已转发给CWG 以澄清意图。 @clockw0rkint x ^= x;
的语法格式不正确。您可以使用初始化程序定义变量(即int x = x;
,尽管它是UB)或xor 赋值表达式语句(即x ^= x;
,尽管如果x
是int
类型,则它是UB,是默认值-已初始化且未事先分配)。您不能将这两者合二为一。
【参考方案1】:
这是作为editorial issue 打开的。它被转发给 CWG 进行(内部)讨论。大约 24 小时后,转发问题的人created a pull request 修改了示例以明确这是 UB:
这里,第二个 \tcodex 的初始化具有未定义的行为,因为初始化程序在其生命周期\irefbasic.life 之外访问第二个 \tcodex。
该 PR 已添加并且问题已关闭。因此,显而易见的解释(由于访问生命周期尚未开始的对象而导致的 UB)似乎是预期的解释。看来委员会的意图是使这些结构不起作用,并且标准的非规范性文本已更新以反映这一点。
【讨论】:
以上是关于在自己的初始化程序中使用变量的主要内容,如果未能解决你的问题,请参考以下文章