Как C ++ проверяет размер массива при передаче по ссылке - PullRequest
0 голосов
/ 12 марта 2020

При передаче массива по ссылке на функцию, например:

void Foo(double (&MyList)[3]);

Код не будет компилироваться при попытке передать массиву, отличному от 3, в эту функцию. Из того, что я смог понять в c ++, нет способа узнать размер массива после его создания.

Как компилятор может отслеживать размер массива? И почему тогда, если он может проверить размер массивов, такой код все равно будет компилироваться?

int MyTab[3]
MyTab[3] = 5;

1 Ответ

5 голосов
/ 12 марта 2020

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)

Компилятор действительно может предупредить вас о большем доступе через границы, хотя и не уверен, почему он этого не делает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...