C++ int foo=foo的标准参考

C++ int foo=foo的标准参考,c++,undefined-behavior,C++,Undefined Behavior,intfoo=foo编译。 C++标准的哪部分允许这个? ? int main() { int foo = foo; } 根据[basic.scope.pdecl],对象foo确实存在于=之后: 名称的声明点是紧跟在其完整声明人之后的(第8条),以及紧跟在其初始值设定人之前的(如有) 但是,整个程序未定义,因为(在RHS上)使用了未初始化的值: intx=x 此处[..]x用其自身(不确定)值初始化 以及: 尽管标准中“推断和未明确规定” 和([conv.lval]): 非函数的左值(3.

intfoo=foo编译。
C++标准的哪部分允许这个?

int main() {
  int foo = foo;
}
根据
[basic.scope.pdecl]
,对象
foo
确实存在于
=
之后:

名称的声明点是紧跟在其完整声明人之后的(第8条),以及紧跟在其初始值设定人之前的(如有)

但是,整个程序未定义,因为(在RHS上)使用了未初始化的值:

intx=x
此处[..]
x
用其自身(不确定)值初始化

以及:

尽管标准中“推断和未明确规定”

和(
[conv.lval]
):

非函数的左值(3.10), 非数组类型T可以转换为 右旋值。如果T是不完整类型, 需要这样做的程序 转换格式不正确。如果 左值所引用的对象是 不是T类型的对象,也不是 从T派生的类型的对象,或如果 对象未初始化,是一个程序 这就需要这种转变 未定义的行为。

具有适当的警告级别;但是,允许编译调用未定义行为的程序。当你运行它们时,它们可以做任何事情


或者,这个呢

int foo = foo;    
int main() {}
请注意,
foo
是一个“全局”。根据
[basic.start.init]
的规定,第一步是零初始化:

具有静态存储持续时间(3.7.1)的对象应在进行任何其他初始化之前进行零初始化(8.5)

因此,您将得到一个值为0的
intfoo
;根据上面的
[basic.scope.pdecl]
[stmt.decl]
,在这一点上它是有效的:

所有的零初始化(8.5) 具有静态存储的本地对象 持续时间(3.7.1)在 任何其他初始化都会发生。[……]

然后将其值初始化为
foo
(自身),即0

这是定义明确的。。。如果有点神秘的话


为了彻底起见,这里是第三个也是最后一个案例:

int foo = 42;
int main() {
   int foo = foo;
}
可悲的是。由于本地
foo
在对初始值设定项求值时已经声明并在范围内,因此初始值设定项使用本地
foo
,并且您仍然被未定义的行为所困扰。不使用全局
foo

3.3.1声明要点[基本范围pdecl]

名称的声明点在其完整声明人(第8条)之后和初始值设定人(如有)之前


如果声明在文件范围内,则行为定义良好。如果在函数作用域中有声明,并且以后使用
foo
(在这种情况下会初始化为某个未指定的值),则行为将是未定义的。

I将+1,但您完全没有提到OP的程序有未定义的行为,因此不应使用。@Tomalak:代码可能有UB,但不一定。OP似乎完全意识到它不是真正应该使用的东西,并且对它编译的纯粹学术观点感到好奇。@Prasoon:
s/program has/program may have/
s/不应该/可能不应该/
。使用
foo
“以后”没有关系;初始化本身调用UB!不是吗?@Prasoon:对,他在初始化中使用了它。他正在用未初始化的
B
初始化
A
(而且
A
B
恰好是同一个对象)。OTOH,如果是全局对象,则行为已定义。@Jerry:我的程序中没有全局对象。如果OP的程序中有全局变量(或者如果他的
foo
声明发生在命名空间范围内),他需要说明这一点,因为它完全改变了问题。@Jerry:好的。那么,我也会为这种情况添加一个子句。@Tomalak:+1。回答得很好。@Jerry:这不是没有帮助,是吗?:)相关:另请参见和