【问题标题】:Standard reference for int foo = fooint foo = foo 的标准参考
【发布时间】:2011-05-31 14:28:21
【问题描述】:

int foo = foo; 编译。 C++ 标准的哪一部分允许这样做?

【问题讨论】:

标签: c++ undefined-behavior


【解决方案1】:

3.3.1 声明点[basic.scope.pdecl]

名称的声明点紧跟在它的完整声明符之后(第 8 条)和它的初始化器(如果有的话)之前,

如果声明在文件范围内,则行为是明确定义的。如果您在函数范围内有声明,并且稍后使用foo [在这种情况下将被初始化为某个未指定的值],则行为将是未定义的。

【讨论】:

  • 我会 +1,但您完全没有提到 OP 的程序具有未定义的行为并且不应使用
  • @Tomalak:代码可能有 UB,但不一定。 OP 似乎完全意识到它不是真正应该使用的东西,并且对它编译的纯粹学术观点感到好奇。
  • @Prasoon: s/program has/program may have/; s/should not/possibly should not/.
  • 使用foo“稍后”没关系;初始化本身会调用 UB!不是吗?
  • @Prasoon:是的,他在初始化时使用了它。他正在用未初始化的B 初始化AAB 恰好是同一个对象)。
【解决方案2】:

这个?

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 是一个“全局”。根据[basic.start.init],这些都是零初始化的第一步:

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

所以你会得到一个值为 0 的int foo;在这一点上,根据上面的[basic.scope.pdecl][stmt.decl],它是有效的:

所有的零初始化(8.5) 具有静态存储的本地对象 持续时间(3.7.1)之前执行 发生任何其他初始化。 [..]

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

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


为了彻底起见,这里是第三种也是最后一种情况:

int foo = 42;
int main() {
   int foo = foo;
}

很遗憾,this is the same as the first case。由于本地 foo 在初始化器被评估时已经声明并在范围内,初始化器使用本地 foo 并且您仍然坚持未定义的行为。未使用全局foo

【讨论】:

  • OTOH,如果它是全局的,则行为已定义。
  • @Jerry:我的程序中没有全局变量。如果 OP 的程序中有全局变量(或者如果他的 foo 声明发生在命名空间范围内),他需要说明这一点,因为它完全改变了问题。
  • @Jerry:好的。那么,我也会为这种情况添加一个条款。
  • @Tomalak:+1。很好的答案。
  • @Jerry: 不是没有帮助,是吗? :)
猜你喜欢
  • 2012-04-04
  • 2011-11-23
  • 2020-06-16
  • 2013-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-26
  • 2011-04-10
相关资源
最近更新 更多