int foo = foo;
编译。
C ++标准的哪一部分允许这个?
答案 0 :(得分:26)
3.3.1声明点[basic.scope.pdecl]
名称的声明点紧跟在完整的声明者(第8条)之后和初始化者之前(如果有的话),
如果声明位于文件范围,则行为已明确定义。如果您在函数范围内有声明,并且稍后使用foo
[在这种情况下将初始化为某些未指定的值],则行为将是未定义的。
答案 1 :(得分:21)
此?
int main() {
int foo = foo;
}
根据foo
,=
之后的对象[basic.scope.pdecl]
确实存在:
名称的声明点在其完整声明者(第8条)之后立即,在其初始化程序之前 (如果有)。
但是,整个程序是未定义的,因为您使用(在RHS上)未初始化的值:
int x = x;
这里[..]x
用自己的(不确定的)值初始化。
和
虽然标准an lvalue-to-rvalue conversion is performed on the RHS expression foo
已经“推断并且不明确”。
和([conv.lval]
):
非功能的左值(3.10), 非数组类型T可以转换为 一个右值。如果T是不完整的类型, 一个需要这个的程序 转换是不正确的。如果 左值所指的对象 不是T类型的对象而不是 从T派生的类型的对象,或 if 该对象未初始化,是一个程序 这需要这种转换 未定义的行为。
有适当的警告级别you will get told about it;但是,允许编译调用未定义行为的程序。当你运行它们时,它们可以做任何事情。
或者,这个怎么样?
int foo = foo;
int main() {}
请注意foo
是“全局”。根据{{1}}:
具有静态存储持续时间(3.7.1)的对象应在进行任何其他初始化之前进行零初始化(8.5)。
所以你得到一个值{0}的[basic.start.init]
;此时,根据上面的int foo
和[basic.scope.pdecl]
,它是有效的:
所有的零初始化(8.5) 具有静态存储的本地对象 持续时间(3.7.1)之前执行 发生任何其他初始化。 [..]
然后将其值初始化为[stmt.decl]
(本身),即0。
这是明确定义的...如果有点神秘。
为了彻底,这是第三个也是最后一个案例:
foo
可悲的是,this is the same as the first case。由于本地int foo = 42;
int main() {
int foo = foo;
}
已在声明初始化程序时已声明并且在范围内,因此初始值设定项使用本地foo
并且您仍然遇到未定义行为。
foo
。