Как std:: end знает конец массива?
std::begin
и std::end
знать начало и конец container
или array
.
Так легко знать end
и begin
для vector
, например, потому что это класс, который дает эту информацию. Но как он знает конец array
, как показано ниже?
int simple_array[5]{1, 2, 3, 4, 5};
auto beg=std::begin(simple_array);
auto en=std::end(simple_array);
std::begin
не так сложно узнать, где начинается массив. Но откуда он знает, где это заканчивается? Будет ли где-нибудь сохранено постоянное целое число 5
?
Я был бы признателен, если бы получил ответ с информацией о низком уровне.
Ответы
Ответ 1
- постоянное целое число 5 будет сохранено где-нибудь, где?
Да, это часть типа массива. Но нет, он не хранится нигде явно. Когда у вас
int i[5] = { };
тип i
равен int[5]
. Ответ Shafik говорит о том, как эта длина используется для реализации end
.
Если у вас С++ 11, использование constexpr
будет простым способом
template <typename T, size_t N>
inline constexpr size_t
arrLen(const T (&arr) [N]) {
return N;
}
Если у вас есть компилятор pre-С++ 11, где constexpr
недоступен, указанная выше функция не может быть оценена во время компиляции. Поэтому в таких ситуациях вы можете использовать это:
template <typename T, size_t N>
char (&arrLenFn(const T (&arr) [N]))[N];
#define arrLen(arr) sizeof(arrLenFn(arr))
Сначала мы объявляем функцию, возвращающую ссылку на массив из N char
i.e. sizeof
эта функция теперь будет длиной массива. Затем у нас есть макрос, чтобы его обернуть, чтобы он читался в конце звонящего.
Примечание. Два массива одного и того же базового типа, но с разной длиной, все еще два совершенно разных типа. int[3]
не совпадает с int[2]
. Array decay, однако, даст вам int*
в обоих случаях. Прочитайте Как использовать массивы на С++?, если вы хотите узнать больше.
Ответ 2
Но как он знает конец массива
Он использует параметр non-type шаблона, чтобы вывести размер массива, который затем можно использовать для создания конечного указателя. Подпись С++ 11 из раздела cppreference для std:: end выглядит следующим образом:
template< class T, std::size_t N >
T* end( T (&array)[N] );
Как отмечает hvd, поскольку он передается по ссылке, это предотвращает распад указателя.
Реализация будет похожа на:
template< class T, std::size_t N >
T* end( T (&array)[N] )
{
return array + N ;
}
Будет ли сохранено постоянное целое число 5 где?
5
или N
является частью типа массива, поэтому N
доступен во время компиляции. Например, применение sizeof к массиву даст нам общее количество байтов в массиве.
Много раз мы видим массив, переданный по значению функции. В этом случае массив распадается на указатель для ввода в массив. Итак, теперь информация о размере теряется. Передача по ссылке позволяет избежать этой потери информации и извлечь размер N
из типа.
Ответ 3
Поскольку вы передаете массив в std::end
, а массив имеет тип T [N]
. std::end
может определить, когда массив закончится, посмотрев на N
в типе.