以下测试代码在VS中正确地执行调试或发布,以及在GCC中。它也适用于带调试的ICC,但在启用优化时却没有(-O2
)。
#include <cstdio>
class tClassA{
public:
int m_first, m_last;
tClassA() : m_first(0), m_last(0) {}
~tClassA() {}
bool isEmpty() const {return (m_first == m_last);}
void updateFirst() {m_first = m_first + 1;}
void updateLast() {m_last = m_last + 1;}
void doSomething() {printf("should not reach here\r\n");}
};
int main() {
tClassA q;
while(true) {
while(q.isEmpty()) ;
q.doSomething();
}
return 1;
}
它应该停在 while(q.isEmpty())
。什么时候 -O2
然而,在ICC(发布)下启用它,无限启动“doSomething”。
由于这是单线程程序 和 isEmpty()
应评估为 true
,我觉得ICC没有理由这样做吗?我想念什么吗?
因为 while (q.isEmpty()) ;
循环不包含任何可能导致外部可见副作用的语句,整个循环优化不存在。这与以下原因相同:
for (int i = 0; i < 10; i++)
;
可以优化不存在,只要 i
不是 volatile
(商店到 volatile
对象是程序“外部可见”效果的一部分。
在C语言中,它实际上是一个突出的争论焦点,是否允许以这种方式优化无限循环(我不知道C ++的情况是什么)。据我所知,在这个问题上从来没有达成共识 - 聪明而知识渊博的人已经采取了双方的立场。
这听起来像个臭虫。这是一个(非常疯狂的)猜测可能导致它的原因......
内联后,它看到:
while (q.m_first == q.m_last) /* do nothing */ ;
do_something();
和任何序列 do nothing repeatedly ; do something
可以简单地翻译成“做某事”。如果重复的部分是无穷无尽的(如在这种情况下),则这会下降。但也许他们没有测试他们编译故意无限循环的例子;-)。
您构建和运行的实际代码有可能在之后丢失分号 while(q.isEmpty())
?这肯定会导致下一行被无限调用。
稍微说一下,这个版本的icc可以满足您的需求。也就是说,它从不打电话 doSomething()
。
[9:41am][wlynch@computer /tmp] icc --version
icc (ICC) 11.0 20081105
C ++标准允许删除没有副作用的循环,即使它们没有终止:
人们普遍认为它是
允许转型很重要
潜在的非终止循环
(例如,通过合并两个循环
迭代相同的潜在
无限集,或通过消除a
无副作用的循环),即使是那样
可能没有其他理由
从来没有第一个循环的情况
终止。
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2429.htm
请参阅此处的讨论:
http://blog.regehr.org/archives/161
最好的办法是将生成的二进制步骤放入其中并拆分主函数并查看生成的汇编。不是说你将能够看到一个错误,但你可以看到是否有一些东西被优化了。
我想这可能是你的gcc版本。我在4.4.2下编译了你的编程,它完全按照应有的方式工作。