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:这不是没有帮助,是吗?:)相关:另请参见和