在自己的初始值设定项中使用变量
Use of variable in own initializer
[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(是预期的解释。委员会似乎打算使这些结构不起作用,并且该标准的非规范性文本已经更新以反映这一点。
- 在自己的初始值设定项中使用变量
- 如何从公共变量自己的类成员函数中访问它们?(C++)
- make 方法不更改自己的类变量而不使它们常量
- 用作自己的初始值设定项的未初始化变量的行为是什么?
- javascript中的静态私有变量用于自己的库
- 读取和分析文件,将解析的字符串的每个部分分配给其自己的变量
- 编写我自己的C++编译器. 卡在变量上
- 将自己的地址放入变量中
- 如何强制 gcc 查找自己的 c++ 头文件,而不覆盖 CXX 变量
- 通过自己的条件变量 c++ 控制每个线程
- 如何编写将"Know"自己的变量名的类
- "auto" lambda 中在其自己的初始值设定项中使用的变量
- 类的继承变量和自己的变量之间的差异
- 每个文件都有自己的静态变量副本吗?
- 递归成员函数无法访问自己的变量
- 将我自己的get/set c++成员函数视为SWIG中的成员变量
- 构建我自己的LPARAM变量
- #ifndef如何处理全局声明的变量和我自己的变量
- 将临时变量写入自己的新变量是不是更好?
- 如何使子进程具有与 parrent 相同的环境变量,并在窗口中拥有自己的环境变量?