1

そのため、前置演算子で大きな頭痛の種に遭遇しました。

Visual C++ 2010 の私のデバッグ ビルドでは。

someArray[++index]

配列インデックスを正しくインクリメントし、それを使用して配列にインデックスを付けます。

私のリリース ビルドでは、配列インデックスを使用し、その後インクリメントしたため、大きな頭痛の種になりました。

奇妙なことに、私のデバッグビルドコードは実際にはしばらく間違っていて、次のように記述していました。

someArray[index++]

これはインデックスを使用してからインクリメントしますが、デバッグ ビルドはまだインデックスをインクリメントしてから値を使用していました。私は今朝まで自分の間違いにさえ気づきませんでした。

これが実際のコードのサンプルです。

for(unsigned int newPointIndex = 0; newPointIndex < newEdgeList.size() - 1;) {
    m_edges.push_back(Edge(newEdgeList[newPointIndex], newEdgeList[++newPointIndex]));
}

for ループではインクリメントは発生しません。配列にインデックスを付けている間、ループ内の実際のコードで発生します。これは巧妙な最適化だと思っていましたが、リリース ビルドでは機能しません。

2 回目に配列にインデックスを作成したときは、リリース ビルドではインクリメントされていないインデックスを使用していましたが、デバッグ ビルドでは機能していました。

4

2 に答える 2

6

あなたの for ループ本体にはこれが含まれます:

Edge(newEdgeList[newPointIndex], newEdgeList[++newPointIndex])

これはundefined unspecified undefined [1] の動作です。これは、2 つの引数がいずれかの順序で (または同時に) 評価される可能性があるためnewPointIndexです。そのため、最初の使用前にインクリメントされたかどうかは明確ではありません。

デバッグおよび最適化されたビルドでは、引数が異なる順序で評価される可能性が非常に高くなります。

newPointIndexforステートメント自体にインクリメントを入れて、本文に書くことをお勧めします:

Edge(newEdgeList[newPointIndex], newEdgeList[newPointIndex + 1])

[1]: un{specified, defined} の議論についてはコメントを読んでください。tl;dr: 聖なる跳躍トカゲ、バットマン!

于 2013-01-25T16:43:06.757 に答える
5

問題は実際にはここにあります:

m_edges.push_back(Edge(newEdgeList[newPointIndex], newEdgeList[++newPointIndex]));

2 つの式のどちらが最初に実行されるかはわかりませnewEdgeList[newPointIndex]newEdgeList[++newPointIndex]

C++ 標準によると、左から右に実行されるという保証はありません。5.2.2/8 を参照:

「後置式と引数式の評価はすべて、相互に順序付けされていません。引数式評価のすべての副作用は、関数が入力される前に順序付けられます」

1.9/15 も関連します。

「関数を呼び出すとき (関数がインラインであるかどうかに関係なく)、すべての値の計算と引数式、または呼び出された関数を指定する後置式に関連付けられた副作用は、すべての式またはステートメントの実行前に順序付けられます。呼び出された関数. [注: 異なる引数式に関連付けられた値の計算と副作用は順序付けされていません。—注の最後]"

これは、実装が、デバッグからリリース ビルドへのこれら 2 つの式の異なる実行順序を持つだけでなく、理論的には、同じプログラム実行でそのステートメントを実行するたびに順序を決定論的な方法でなく自由に変更できることを意味します。 .

解決策は、これらのサブ式からインクリメントを取り出すことです(別の回答で指摘されているように)。

于 2013-01-25T16:43:25.447 に答える