1
class CheckPointer {
public:
    CheckPointer(int * mbeg, int * mend) :
        beg(mbeg), end(mend), curr(mbeg) {}

    // subscript operator
    int & operator[] (const size_t pos) {
        if (beg + pos < beg) {
            throw out_of_range("ERR: before beg!");
        }
        if (beg + pos >= end)
            throw out_of_range("ERR: end or past end!");
        return *(const_cast<int *>(beg + pos));
    }
private:
    const int * beg;
    const int * end;
    int * curr;
};

CheckPointerクラスの添え字演算子を定義しました。@param posのタイプはsize_tであるため、ユーザーが正の値を渡したのか負の値を渡したのかを確認できません。ただし、代わりに境界チェックを実行するコードを記述しようとすると、機能します。

        if (beg + pos < beg) {
            throw out_of_range("ERR: before beg!");
        }

なぜそれが機能するのかわかりません...誰かが私を助けてくれますか?

私の質問を検討していただきありがとうございます!


詳細については:

環境:Eclipse CDT、Ubuntu 10.04

テストコード:

int iarr[6] = {1, 2, 3, 4, 5, 6};
CheckPointer cp(iarr, iarr+6);
// subscript
cout << cp[2] << endl;
cout << cp[5] << endl;
cout << cp[-2] << endl; // error: before beg

test-code_output:

terminate called after throwing an instance of 'std::out_of_range'
  what():  ERR: before beg!
3
6
4

2 に答える 2

2

これは、負の値が符号なしの値にキャストされるために機能します。お使いのマシンアーキテクチャでは、負の値に2の補数を使用している可能性があるため、値が-2の場合は次のようになります。

0xfffffffe (assuming 32-bit)

これをに追加するとbeg、ラップアラウンドし、beg2以上の場合は、2を引く効果があります。したがって、インデックスが非常に大きいにもかかわらず、本質的に減算を実行しました。の値がまたはの場合beg1エラー0は代わりに「過去の終わり」になります。

于 2012-11-25T22:23:06.353 に答える
1

正式には、で始まる配列の外側にある場合、との比較は未定義の動作beg + posになります(これは少し単純化されていますが、この説明には十分です)。不良インデックスのより良いチェックは次のようになります。begbeg + posbeg

if (end - beg <= pos)

しかし、それは質問に答えません。小さな負の値を変換しsize_tて大きな正の値を生成します。それらをオフセットとして扱うと、配列の終わりをはるかに超えたポインターが生成されるため、結果が範囲内にあるかどうかを確認すると、この問題と、単に終わりを超えた「通常の」値が見つかります。

于 2012-11-25T23:05:20.123 に答える