4

順序付き配列を使用するクリーク分割プログラムのパフォーマンスを向上させるために、ループの停止条件に、forループ先の配列の要素へのアクセスを含めました。

int myValue = 13;

for (int i=0; array[i] < myValue; i++)
{
    //performing operations on the array
}

私の配列には 未満の値しか含まれていない可能性があるため、これは明らかに安全ではありませんmyValue

int myValue = 13;

for (int i=0; i < array.size() && array[i] < myValue; i++)
{
    //performing operations on the array
}

この実装では、すべてがうまくいっているように見えますが、条件を切り替えると、最初の例と同じ問題に陥ります。

int myValue = 13;

for (int i=0; array[i] < myValue && i < array.size(); i++)
{
    //performing operations on the array
}

iしたがって、これは明らかにコンパイラが 2 つの条件の順序を設定する方法によるものであると推測しました。最後のケースでは、が配列のサイズより大きくない場合にのみループに入るように要求しても、 m 以前に、配列の範囲外である可能性のある値を読み取っています。

私の質問は次のとおりです。2 番目の実装で行ったように、常に安全に実行できますか?それとも、コンパイラが制御条件を切り替えて、安全でないコードにつながることがありますか?

ありがとう。

4

2 に答える 2

7

(&&論理 AND) 演算子は、可能であれば常に短絡します。2 番目の例は安全です。

これはプリミティブ型のみに適用され、ブール演算子をオーバーロードする型には適用されないことに注意してください。

標準的な引用がなければ、自尊心のあるC++答えは完成しないためです。

5.14.1 (論理 AND) && 演算子は左から右にグループ化します。オペランドは両方とも、コンテキストに基づいて bool 型に変換されます (条項 4)。両方のオペランドが true の場合、結果は true になり、それ以外の場合は false になります。& とは異なり、&& は左から右への評価を保証します。最初のオペランドが false の場合、2 番目のオペランドは評価されません。

5.14.2 (論理 OR) || 演算子グループは左から右へ。オペランドは両方とも文脈上 bool に変換されます (条項 4)。オペランドのいずれかが true の場合は true を返し、それ以外の場合は false を返します。|とは異なり、|| 左から右への評価を保証します。さらに、最初のオペランドが true と評価された場合、2 番目のオペランドは評価されません。

于 2012-11-01T00:13:29.597 に答える
0

私はどちらの例もしません。これを行う:

for (int i=0; i < array.size(); i++) {
    if (array[i] >= myValue) {
        break;
    }

    // do stuff
}

これにより、混乱や安全性の欠如がなくなります。他の例と同じ速度ですが、後でデバッグする方がはるかに簡単です。

于 2012-11-01T00:17:50.987 に答える