Question

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;
};

I have defined a subscript operator for the class CheckPointer. As the @param pos is of type size_t, I cannot check whether the user has passed a positive or negative value. Howerver I try to write the code to do the bound-check instead and it works :

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

I don't know why it works... Could any one help me?

Thank you for considering my question!


For more information:

Environment: eclipse CDT, Ubuntu 10.04

test-code:

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
Was it helpful?

Solution

This works because the negative value is cast to an unsigned value. Your machine architecture probably uses two's-complement for negative values, so a value of -2 results in:

0xfffffffe (assuming 32-bit)

When you add this to beg, it wraps around and provided beg is greater than or equal to 2, has the effect of subtracting 2 from it. Thus, despite the index being extremely large, it has essentially performed a subtraction. If the value of beg was 1 or 0, the error would be "past end" instead.

OTHER TIPS

Formally, comparing beg + pos to beg has undefined behavior if beg + pos is outside the array that starts at beg (that's slightly simplified, but sufficient for this discussion). A better check for a bad index would be:

if (end - beg <= pos)

But that doesn't answer the question. Converting small negative values to size_t produces large positive values; treating them as offsets produces a pointer that's well past the end of the array, so checking whether the result is in bounds will find this problem as well as "ordinary" values that are simply beyond the end.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top