In che modo std :: end conosce la fine di un array?

std::begin e std::end conoscono l’inizio e la fine di un container o di un array .

È così facile conoscere la end e l’ begin di un vector ad esempio perché è una class che fornisce queste informazioni. Ma come fa a sapere la fine di un array come il seguente?

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

std::begin non è così difficile sapere dove inizia l’array. Ma come fa a sapere dove finisce? Il numero intero costante 5 verrà memorizzato da qualche parte?

Apprezzerei se avessi una risposta con alcune informazioni di basso livello.

è il numero intero costante 5 verrà memorizzato un po ‘dove?

Sì, fa parte del tipo di array. Ma no, non è memorizzato da nessuna parte in modo esplicito. Quando hai

 int i[5] = { }; 

il tipo di i è int[5] . La risposta di Shafik parla di come questa lunghezza viene utilizzata per implementare la end .

Se hai C ++ 11, usare constexpr sarebbe la strada più semplice

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

Se hai un compilatore pre-C ++ 11 in cui constexpr non è disponibile, la funzione sopra riportata potrebbe non essere valutata in fase di compilazione. Quindi in tali situazioni, puoi usare questo:

 template  char (&arrLenFn(const T (&arr) [N]))[N]; #define arrLen(arr) sizeof(arrLenFn(arr)) 

Per prima cosa dichiariamo una funzione che restituisce un riferimento a un array di N char , cioè la dimensione di questa funzione sarebbe ora la lunghezza dell’array. Quindi abbiamo una macro per avvolgerla, in modo che sia leggibile alla fine del chiamante.

Nota: due matrici dello stesso tipo di base ma con diverse lunghezze sono ancora due tipi completamente diversi. int[3] non è la stessa di int[2] . Il decadimento delle matrici , tuttavia, ti int* un int* in entrambi i casi. Leggi Come uso gli array in C ++? se vuoi saperne di più

Ma come fa a sapere la fine di un array

Utilizza un parametro non di tipo template per dedurre la dimensione dell’array, che può quindi essere utilizzato per produrre il puntatore finale. La firma C ++ 11 dalla sezione cppreference per std :: end è la seguente:

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

Come nota hvd, dato che è passato per riferimento, impedisce il decadimento di un puntatore.

L’implementazione sarebbe qualcosa di simile a:

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

Il numero intero costante 5 verrà memorizzato in alcuni dove?

5 o N fa parte del tipo dell’array e quindi N è disponibile in fase di compilazione. Ad esempio, l’applicazione di sizeof a un array ci darà il numero totale di byte nell’array.

Molte volte vediamo un array passato per valore a una funzione. In tal caso, l’array decade in un puntatore per digitare archiviato nell’array. Quindi ora le informazioni sulla dimensione sono perse. Il passaggio per riferimento ci consente di evitare questa perdita di informazioni e di estrarre la dimensione N dal tipo.

Perché stai passando un array a std::end e un array ha tipo T [N] . std::end può dire quando l’array termina guardando N nel tipo.