更新,见下文!
我听说并读过C++ 0x允许编译器为以下代码段打印"Hello"
#include <iostream>
int main() {
while(1)
;
std::cout << "Hello" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
它显然与线程和优化功能有关.在我看来,这可能让许多人感到惊讶.
有人能够很好地解释为什么必须允许这样做吗?作为参考,最新的C++ 0x草案说明了6.5/5
在for语句的情况下,在for-init语句之外的循环,
- 不调用库I/O函数,和
- 不访问或修改易失性对象,以及
- 不执行同步操作(1.10)或原子操作(第29条)
可以通过实现来假设终止.[注意:这是为了允许编译器转换,例如删除空循环,即使无法证明终止也是如此. - 结束说明]
编辑:
这篇富有洞察力的文章谈到了标准文本
不幸的是,没有使用"未定义的行为".但是,只要标准说"编译器可以假设P",就暗示具有非-P属性的程序具有未定义的语义.
这是正确的,是否允许编译器为上述程序打印"Bye"?
这里有一个更有见地的线索,这是关于C的类似改变,由Guy完成上述链接文章开始.在其他有用的事实中,他们提出了一个似乎也适用于C++ 0x的解决方案(更新:这将不再适用于n3225 - 见下文!)
endless:
goto endless;
Run Code Online (Sandbox Code Playgroud)
看来,编译器不允许优化它,因为它不是循环,而是跳转.另一个人总结了C++ 0x和C201X的建议更改
通过编写一个循环,程序员断言或者环路不可见的东西的行为(执行I/O,访问volatile对象,或执行同步或原子操作), 或者,它最终会终止.如果我通过编写一个没有副作用的无限循环来违反这个假设,我对编译器撒谎,而我的程序的行为是未定义的.(如果我很幸运,编译器可能会警告我.)语言不提供(不再提供?)表达无可见行为的无限循环的方法.
2011年3月3日更新为n3225:委员会将案文移至1.10/24并说
实现可以假定任何线程最终将执行以下操作之一:
- 终止,
- 调用库I/O函数,
- 访问或修改易失性对象,或
- 执行同步操作或原子操作.
的goto把戏,不工作了!
在测试我的代码时,我注意到当for loop删除空的范围时,执行时间显着增加.通常我会认为编译器会注意到for循环没有用处,因此会被忽略.作为编译器标志我正在使用-O3(gcc 5.4).我还使用向量而不是集合来测试它,这似乎可以工作并在两种情况下都给出相同的执行时间.似乎迭代器的增量花费了所有额外的时间.
第一种情况下,ranged for循环仍然存在(慢):
#include <iostream>
#include <set>
int main () {
long result;
std::set<double> results;
for (int i = 2; i <= 10000; ++i) {
results.insert(i);
for (auto element : results) {
// no operation
}
}
std::cout << "Result: " << result << "\n";
}
Run Code Online (Sandbox Code Playgroud)
第二种情况,删除了范围for循环(快速):
#include <iostream>
#include <set>
int main () {
long result;
std::set<double> results;
for (int i = 2; i <= 10000; ++i) {
results.insert(i);
}
std::cout …Run Code Online (Sandbox Code Playgroud)