11

次のテスト コードは、デバッグまたはリリースを使用して 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())です。ただし、ICC (リリース) で有効にする-O2と、無限に "doSomething" を開始します。

これはシングル スレッド プログラムであり isEmpty()、として評価する必要があるtrueため、ICC がこのように動作する理由がわかりません。私は何かが恋しいですか?

4

7 に答える 7

9

while (q.isEmpty()) ;ループには、外部から見える副作用を引き起こす可能性のあるステートメントが含まれていないため、ループ全体が最適化されて存在しなくなります。次の理由と同じです。

for (int i = 0; i < 10; i++)
    ;

iそうでない限り、存在しないように最適化できますvolatile(オブジェクトへのストアvolatileは、プログラムの「外部から見える」効果の一部です)。

C 言語では、この方法で無限ループを最適化して取り除くことができるかどうかは、実際には顕著な争点です (C++ の状況はわかりません)。私の知る限り、この問題についてコンセンサスに達したことはありません。賢明で知識豊富な人々が双方の立場を取りました。

于 2010-08-20T03:16:28.497 に答える
2

それは確かにバグのように聞こえます。これは、どのような推論がそれにつながったのかについての(かなりワイルドな)推測です...

インライン化すると、次のようになります。

while (q.m_first == q.m_last) /* do nothing */ ;
do_something();

の任意のシーケンスはdo nothing repeatedly ; do something、単に「何かをする」に変換できます。これは、繰り返される部分が無限の場合 (この場合のように) 低下します。しかし、おそらく彼らは、意図的に無限ループを行う例でコンパイルをテストしていません ;-)。

于 2010-08-20T02:55:29.210 に答える
1

C++ 標準では、終了しない場合でも、副作用のないループを削除できます。

一般に、終了しない可能性のあるループの変換を許可することが重要であると考えられています (たとえば、同じ潜在的に無限のセットを反復する 2 つのループをマージすることによって、または副作用のないループを排除することによって)。それ以外の場合は、最初のループが終了しない場合に正当化されます。 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2429.htm

ここでの議論を参照してください: http://blog.regehr.org/archives/161

于 2010-08-21T06:12:48.783 に答える
1

ビルドして実行した実際のコードの後に​​セミコロンがない可能性はありますwhile(q.isEmpty())か? それは確かに、次の行が無限に呼び出されることになります。

于 2010-08-20T03:05:29.400 に答える
1

ちょっと余談ですが、このバージョンの icc はあなたが望むことをします。つまり、 を呼び出すことはありませんdoSomething()

[9:41am][wlynch@computer /tmp] icc --version
icc (ICC) 11.0 20081105
于 2010-08-20T13:42:57.373 に答える
0

あなたの最善の策は、結果のバイナリ ステップをそれに取り込んでメイン関数を逆アセンブルし、どのアセンブリが生成されたかを確認することです。バグを確認できるとは言いませんが、何かが最適化されているかどうかは確認できます。

于 2010-08-20T02:53:22.117 に答える
-3

お使いのバージョンの gcc だったのかもしれません。私はあなたのプログラムを 4.4.2 でコンパイルしました。

于 2010-08-20T03:02:10.117 に答える