已更新,见下文!
我听说并读到 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 属性的程序具有未定义的语义。
这是正确的,编译器是否允许为上述程序打印“Bye”?
这里有一个更有洞察力的线程,它是关于对 C 的类似更改,由完成上述链接文章的 Guy 开始。在其他有用的事实中,他们提出了一个似乎也适用于 C++0x 的解决方案(更新:这将不再适用于 n3225 - 见下文!)
endless:
goto endless;
似乎不允许编译器对其进行优化,因为它不是循环,而是跳转。另一个人总结了 C++0x 和 C201X 中的提议更改
通过编写循环,程序员要么断言循环做了一些具有可见行为的事情(执行 I/O、访问易失性对象,或者执行同步或原子操作), 要么它最终终止。如果我通过编写一个没有副作用的无限循环来违反该假设,那么我就是在对编译器撒谎,并且我的程序的行为是未定义的。(如果我很幸运,编译器可能会警告我。)该语言不提供(不再提供?)一种在没有可见行为的情况下表达无限循环的方法。
更新 3.1.2011 与 n3225:委员会将文本移至 1.10/24 并说
实现可能假设任何线程最终都会执行以下操作之一:
- 终止,
- 调用库 I/O 函数,
- 访问或修改 volatile 对象,或
- 执行同步操作或原子操作。
这个goto
技巧将不再起作用!