0

Why doesn't the compiler stop me from indexing into an array using integers greater than the length of the array minus one and negative integers?

What is the rationale behind allowing this?

  • You're talking about overflowing the buffer? – emsimpson92 Aug 28 '18 at 23:27
  • 7
    One of the guiding principles of C and C++ is that you don't pay for what you don't use. Performing out of bounds checks tests take time, and thus are a penalty for programs that are well formed. – user4581301 Aug 28 '18 at 23:27
  • 1
    Consider indexing on a pointer: `int *p = some value;`. `p[-10]` can be perfectly valid as long as `p` points to the middle of an array – Justin Aug 28 '18 at 23:28
  • Looking at this from the compile-time side, though, the compiler COULD with no runtime penalty, detect some simple out-of-bounds errors. For example where a `for` loop has indexing that will pierce a buffer of size known to the function and known at compile time. It's not required by the standard and it's probably fairly tricky, but sooner or later someone will add it into a compiler as a warning. Not ethough that the requirements are pretty strict, so its use is pretty much limited to parlour tricks. It could not reliably pick off an array passed into a function, for example. – user4581301 Aug 28 '18 at 23:37
  • 2
    Various "sanitizers" can detect this for you, but at a cost. – Michael Dorgan Aug 28 '18 at 23:39

2 Answers2

5

Well the compiler can't because that's a runtime provision.

But why does the std::vector not bounds check the [] operator. This is because there is already a bounds checked method at(). This performs bounds checking and throws an exception if the index is out of bounds.

But the C++ principle of not paying for what you don't use is also at play. Why should you check for an out of bounds exception if you have already guaranteed it is in bounds.

for(int loop = 0; loop < cont.size(); ++loop) {
    std::cout << cont[loop] << "\n";   // Do I need to bounds check here?
}                                      // loop is guaranteed to be in range
                                       // why should I pay for the cost of
                                       // of a check? So beginners don;t make
                                       // mistakes?

So if you want bounds checked access use at() if you want unchecked use [].

From the comments:

Why does p[-10] work? Because on pointer types this is simply syntactic sugar for *(p - 10). That a lot harder to check for validity then you think.

int  q[] = {1,2,3,4,5,6,7,8,9,10,11,12,13};
int* p   = q + 11;

std::cout << p[-10]; // This is valid operation.
Justin
  • 24,288
  • 12
  • 92
  • 142
Martin York
  • 257,169
  • 86
  • 333
  • 562
2

The C++ runtime does not keep track of the size of arrays, so there is no way to prevent indexing past the end of the array.

Indexing negative values can be useful if you have a pointer to a location in the middle of an array. For example:

int a[] = { 1, 2, 3, 4, 5 };
int *p = &a[2];
std::cout << p[-1] << std::endl;

This will print 2, since p points to the element containing 3.

Antonin GAVREL
  • 9,682
  • 8
  • 54
  • 81
dbush
  • 205,898
  • 23
  • 218
  • 273