Given this valid C or C++ code
int x() {
int numbers[3]; // Lets suppose numbers are filled in with values
int sum = 0;
for (const int* p = &numbers[0]; p != &numbers[3]; ++p)
sum += *p;
return sum;
}
This code uses pointer arithmetics and as far as I know it is valid to have a pointer point to the one past last element inside an array, referencing that pointer is uspecified but we can have a pointer point to that position. So, &p[0], &p[1], &p[2] and &p[3] are valid pointers, and p[0], p[1] and p[2] are valid values.
If I replace the int array with a std::vector everything should be fine, we get this code
#include <vector>
int x() {
std::vector<int> numbers(3);
int sum = 0;
for (const int* p = &numbers[0]; p != &numbers[3]; ++p)
sum += *p;
return sum;
}
But running under Visual C++ 2017 in DEBUG mode I get this exception "vector subscript out of range", that is triggered from MS STL library because the implementation asumes that using operator[] we are automatically referencing the underlaying value, wich is not the case. This is MS STL code that do the bounds check ...
_NODISCARD _Ty& operator[](const size_type _Pos)
{ // subscript mutable sequence
#if _ITERATOR_DEBUG_LEVEL == 2
if (size() <= _Pos)
{ // report error
_DEBUG_ERROR("vector subscript out of range");
}
#elif _ITERATOR_DEBUG_LEVEL == 1
_SCL_SECURE_VALIDATE_RANGE(_Pos < size());
#endif /* _ITERATOR_DEBUG_LEVEL */
return (this->_Myfirst()[_Pos]);
}
I don´t get the error if I replace &numbers[0] and &numbers[3] with numbers.begin() and numbers.end().
I agree this is really ugly code, but I simplify the real code just to expose the bug.
The original code was using &vec[0] on a vector with zero elements.
So my question is:
Is this a BUG on Microsoft Visual C++ STL implementation or there is some restriction on operator[] for vectors<>?
I know that replacing [] by at() would be a bug, but I understand &vec[size] should still be valid for std::vector<>
&p[3]
is a valid pointer, becausep[3]
is invalid to start with.p+3
is a valid pointer, that points to the intended location though, as isvec.begin()+3
– Mooing Duckauto sum = std::accumulate(std::begin(container_name), std::end(container_name), container_name::value_type{});
– NathanOliver0
and notcontainer_name::value_type{}
– Calethstd::value_type
type trait that would give use the type for containers or arrays. Generic programing FTW. – NathanOliver