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

测试代码输出:

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

2 回答 2

2

这是有效的,因为负值被转换为无符号值。您的机器架构可能对负值使用二进制补码,因此值 -2 会导致:

0xfffffffe (assuming 32-bit)

当您将此添加到 时beg,它会环绕并提供beg大于或等于 2 的值,具有从中减去 2 的效果。因此,尽管索引非常大,但它基本上执行了减法。如果值为或,beg则错误将是“过去的结尾”。10

于 2012-11-25T22:23:06.353 回答
1

形式上,如果在开始的数组之外,beg + pos比较beg具有未定义的行为(这稍微简化了,但对于本次讨论来说已经足够了)。对坏索引的更好检查是:beg + posbeg

if (end - beg <= pos)

但这并不能回答问题。将小的负值转换为size_t产生大的正值;将它们视为偏移量会产生一个远远超出数组末尾的指针,因此检查结果是否在边界内会发现这个问题以及简单超出末尾的“普通”值。

于 2012-11-25T23:05:20.123 回答