0

I learned something interesting today: if I have a standard vector v and I run code like:

std::vector<float> v;
for (int i = 0; i < 2; i++) v.push_back(2.);

if I call v[2] I will not get a segmentation fault, because the operator[] does not do bounds checking. I was getting some absurdly small number, but I was curious what the default behavior of push_back is and what I should expect from overflowing a vector bounds. I would assume it would have to allocate more space than just the next float. How much? Is this in the standard, or is it compiler-specific?

webb
  • 450
  • 1
  • 3
  • 12
  • 3
    You should expect undefined behaviour. Nothing more, nothing less. – chris Mar 28 '13 at 21:31
  • Try compiling without optimizations, your standard library implementation *may* do bounds checking for `vector::operator[]` in that case. Anyway, once the bounds checking is discarded your code has undefined behavior. – Praetorian Mar 28 '13 at 21:33
  • What you've hopefully learned (it's a very valuable lesson) is that Undefined Behaviour does not mean your program will crash. It does mean exactly what it says, the behaviour of your program is undefined. Simple as it is, some people struggle with this concept. – john Mar 28 '13 at 21:41
  • if you want bounds checking you can use vector::at. v.at(n) will throw an exception if out of range. – bdwain Mar 29 '13 at 04:12

2 Answers2

3

I learned something interesting today

So it's time to learn something even more interesting: your code has Undefined Behavior, because the precondition for using the subscript operator is that the index is smaller than the size of the vector.

Per Table 101 of the C++11 Standard, the expression a[n] is equivalent to *(a.begin() + n). Since v.begin() + 2 is an iterator to a position beyond the end of the container v, dereferencing it results in Undefined Behavior.

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • So how much memory does push_back allocate when it's called? Is it just enough for one more of whatever is contained in the vector, or is it compiler-dependent? I assume it doesn't reallocate memory for the vector with one extra element, copies the vector, and deallocates every single time. – webb Mar 28 '13 at 22:44
  • 1
    @webb: Most of the time, a call to `push_back()` results in no memory allocation at all - the vector already allocated a contiguous memory region, and that's where the new element is going to be pushed. However, if the memory previously allocated is full and the vector exceeds its capacity, `push_back()` will cause a new allocation of a contiguous region of memory large enough to contain the current content plus the new element *and* a certain number (implementation-dependent) of other elements. Then, the elements of the vector are *moved* into the new allocated storage. – Andy Prowl Mar 28 '13 at 22:48
0

if I call v[2] I will not get a segmentation fault, because the operator[] does not do bounds checking

Those two aren't related like this...

Your code invokes undefined behavior, so it can do anything.