C ++ может отслеживать размер массивов только с помощью автоматического c или stati c срока хранения (т. Е. Локальных или глобальных переменных), потому что это единственное место, где могут существовать массивы фиксированного размера (и, следовательно, переменные типа массива могут только ссылаться на тех). Смущает то, что массивам разрешается распадаться на указатели, что может происходить очень быстро (например, если вы передаете массив как аргумент функции без параметра ссылка на массив).
void foo(int i[]); // i will be a pointer, not an array
template <std::size_t N>
void foo(int (&i)[N]); // i is a reference to an array with size N
Массивы с динамическим c сроком хранения (т. Е. На массивы, созданные с помощью new
) нельзя ссылаться по типу массива, поскольку такой массив должен иметь известный размер времени компиляции, а new
может создавать динамические c массивы (размер, возможно, известен только во время выполнения). Из-за этого new
дает вам указатель на первый элемент массива, и в этот момент компилятор больше не может вам помочь.
int i[] = new int[10]; // i is not an array, it's a pointer
int i[10]; // i is an array, the array is located on the stack
Относительно вашего
int MyTab[3];
MyTab[3] = 5;
пример, давайте процитируем cppreference :
Встроенное нижнее выражение E1 [E2] в точности совпадает с выражением * (E1 + E2)
В переводе на ваш случай:
MyTab[3]
идентичен *(MyTab + 3)
, и здесь снова наступает наш прекрасный распад указателя. operator+
работает с указателем и интегралом, поэтому MyTab
снова распадается на указатель, теряя всю информацию о его размере.
Кроме того, вы все равно можете получить конечный итератор за счет отсутствия доступа (вам просто не разрешено читать или записывать значение):
int* begin = MyTab; // pointer decay again, equal to &MyTab[0]
int* end = &MyTab[3]; // get a pointer to one past the end (aka end iterator)
Компилятор действительно может предупредить вас о большем доступе через границы, хотя и не уверен, почему он этого не делает.