¿Cómo sabe std::end el final de una matriz?

Resuelto Humam Helfawi asked hace 9 años • 3 respuestas

std::beginy std::endconocer el principio y el final de un contenedor o una matriz.

Es fácil conocer el endy beginde un vector, por ejemplo, porque es una clase que proporciona esta información. Pero, ¿cómo sabe el final de un arreglo como el siguiente?

int simple_array[5]{1, 2, 3, 4, 5};
auto beg = std::begin(simple_array);
auto en = std::end(simple_array);

std::beginNo es tan difícil saber dónde comienza la matriz. ¿Pero cómo sabe dónde termina? ¿Se almacenará el número entero constante 5en algún lugar?

Agradecería recibir una respuesta con información de bajo nivel.

Humam Helfawi avatar Nov 03 '15 17:11 Humam Helfawi
Aceptado

Pero, ¿cómo sabe el final de una matriz?

Utiliza un parámetro de plantilla que no es de tipo para deducir el tamaño de la matriz, que luego puede usarse para producir el puntero final. La firma C++11 de la sección cppreference para std::end es la siguiente:

template< class T, std::size_t N >
T* end( T (&array)[N] );

Como señala hvd, dado que se pasa por referencia, esto evita la caída en un puntero.

La implementación sería algo similar a:

template< class T, std::size_t N >
T* end( T (&array)[N] )
{
    return array + N ;
}

¿Se almacenará el número entero constante 5 en algún lugar?

5o Nes parte del tipo de matriz y, por lo tanto, Nestá disponible en el momento de la compilación. Por ejemplo, aplicar sizeof a una matriz nos dará el número total de bytes en la matriz.

Muchas veces vemos un array pasado por valor a una función. En ese caso, la matriz se descompone en un puntero al tipo almacenado en la matriz. Entonces ahora se pierde la información del tamaño. Pasar por referencia nos permite evitar esta pérdida de información y extraer el tamaño Ndel tipo.

Shafik Yaghmour avatar Nov 03 '2015 10:11 Shafik Yaghmour

¿Se almacenará el número entero constante 5 en algún lugar?

Sí, es parte del tipo de matriz. Pero no, no está almacenado explícitamente en ningún lugar. Cuando tengas

int i[5] = { };

el tipo de ies int[5]. La respuesta de Shafik habla de cómo se utiliza esta longitud para implementar end.

Si tienes C++ 11, usarlo constexprsería la forma más sencilla de hacerlo.

template <typename T, size_t N>
inline constexpr size_t
arrLen(const T (&arr) [N]) {
    return N;
}

Si tiene un compilador anterior a C++ 11 que constexprno está disponible, es posible que la función anterior no se evalúe en tiempo de compilación. Entonces, en tales situaciones, puedes usar esto:

template <typename T, size_t N>
char (&arrLenFn(const T (&arr) [N]))[N];

#define arrLen(arr) sizeof(arrLenFn(arr))

Primero declaramos una función que devuelve una referencia a una matriz de N chars, es decir, sizeofesta función ahora sería la longitud de la matriz. Luego tenemos una macro para envolverlo, de modo que sea legible al final de la persona que llama.

Nota: Dos matrices del mismo tipo base pero con diferentes longitudes siguen siendo dos tipos completamente diferentes. int[3]no es lo mismo que int[2]. Sin embargo, la decadencia de la matriz le daría un resultado int*en ambos casos. Lea ¿Cómo uso matrices en C++? si quieres saber más.

legends2k avatar Nov 03 '2015 10:11 legends2k

Porque le está pasando una matriz std::endy una matriz tiene tipo T [N]. std::endPuedes saber cuándo termina la matriz mirando el Ntipo.

Simple avatar Nov 03 '2015 10:11 Simple