更新,见下面!
我听说和读到,C + + 0x 允许编译器为下面的代码片段打印“ Hello”
#include <iostream>
int main() {
while(1)
;
std::cout << "Hello" << std::endl;
}
它显然与线程和优化能力有关。不过在我看来,这可能会让很多人感到惊讶。
有人能解释一下为什么有必要允许这样做吗?作为参考,最新的 C + + 0x 草案说在 6.5/5
在 for 语句的情况下,在 for-init 语句之外的一个循环,
- 不调用库 I/O 函数,并且
- 不访问或修改易失性对象,并且
- 不执行同步操作(1.10)或原子操作(条款29)
可能被实现假定为终止。[注意: 这是为了允许编译器转换- 即使无法证明终止,也可以删除空循环。ーー结束注释]
编辑:
这篇有见地的文章 谈到了标准文本
不幸的是,“未定义行为”这个词并没有被使用。然而,任何时候标准说“编译器可以假设 P”,这意味着具有非 P 属性的程序具有未定义的语义。
是否正确,编译器是否允许为上面的程序打印“再见”?
还有一个更有见地的 这里有线,这是一个类似于 C 的变化,由 Guy 开始完成上面的链接文章。在其他有用的事实中,他们提出了一个似乎也适用于 C + + 0x 的解决方案(更新: 这在 n3225中不再有效——见下文!)
endless:
goto endless;
编译器似乎不允许优化它,因为它不是一个循环,而是一个跳转。另一个人总结了 C + + 0x 和 C201X 中提出的更改
通过编写一个循环,程序员断言 都不是 Loop 使用可见行为执行某些操作(执行 I/O,访问 或执行同步操作或原子操作) , 如果我违背了这个假设 通过编写一个没有副作用的无限循环,我在欺骗 编译器,我的程序的行为是未定义的。(如果我幸运, 编译器可能会警告我) (不再提供?)表达无限循环的方法 看得见的行为。
2011年3月1日 n3225更新: 委员会将文本移至1.10/24,并说
实现可能假设任何线程最终将执行下列操作之一:
- 终结,
- 调用库 I/O 函数,
- 访问或修改易失性对象,或
- 执行同步操作或原子操作。
goto
的技巧将 没有工作了!