Pourquoi la dimension d'un tableau fait-elle partie de son type?

14

En lisant le livre C ++ Primer, je suis tombé sur cette déclaration: "Le nombre d'éléments dans un tableau fait partie du type du tableau." Je voulais donc savoir en utilisant le code suivant:

#include<iostream>

int main()
{
    char Array1[]{'H', 'e', 'l', 'p'};
    char Array2[]{'P', 'l', 'e', 'a', 's', 'e'};

    std::cout<<typeid(Array1).name()<<std::endl;        //prints  A4_c
    std::cout<<typeid(Array2).name()<<std::endl;        //prints  A6_c

    return 0;
}

Et fait intéressant, le résultat de typeid sur les deux tableaux a montré qu'ils sont en quelque sorte différents.

  • Que se passe-t-il dans les coulisses?
  • Pourquoi est-il nécessaire pour les tableaux d'avoir un type qui inclut sa taille? Est-ce simplement parce que sa taille ne doit pas changer?
  • Comment cela affectera-t-il la comparaison des tableaux?

Je veux juste pouvoir comprendre le concept en profondeur.

poulpe
la source
3
Il n'est pas strictement nécessaire d'inclure des informations de taille dans le type, mais c'est utile
byxor
Tout tutoriel sur les tableaux expliquera (1). Je ne sais pas ce que vous entendez par (3), car il n'y a aucun moyen intégré de comparer les tableaux.
HolyBlackCat

Réponses:

20

Que se passe-t-il dans les coulisses?

Un attribut non alloué dynamiquement est, par définition, un conteneur de taille fixe d'éléments homogènes. Un tableau d' Néléments de type Test disposé en mémoire sous la forme d'une séquence contiguë d' Nobjets de type T.


Pourquoi est-il nécessaire que les tableaux aient un type qui inclut leur taille?

Je ne pense pas qu'il soit "nécessaire" pour qu'un type de tableau inclue sa taille - en fait, vous pouvez utiliser un pointeur pour faire référence à une séquence contiguë d' Tobjets. Un tel pointeur perdrait des informations de taille sur le tableau.

C'est cependant une chose utile à avoir. Il améliore la sécurité des types et code des informations utiles au moment de la compilation qui peuvent être utilisées de plusieurs manières. Par exemple, vous pouvez utiliser des références à des tableaux pour surcharger des tableaux de différentes tailles

void foo(int(&array)[4]) { /* ... */ }
void foo(int(&array)[8]) { /* ... */ }

ou pour déterminer la taille d'un tableau en tant qu'expression constante

template <typename T, std::size_t N>
constexpr auto sizeOf(const T(&array)[N]) { return N; }

Comment cela affectera-t-il la comparaison des tableaux?

Ce n'est pas vraiment le cas.

Vous ne pouvez pas comparer des tableaux de style C de la même manière que vous compareriez deux nombres (par exemple des intobjets). Il faudrait écrire une sorte de comparaison lexicographique et décider ce que cela signifie pour des collections de différentes tailles. std::vector<T>prévoit que , et la même logique peut être appliquée aux tableaux.


Bonus: C ++ 11 et supérieur fournit std::array, qui est un wrapper autour d'un tableau de style C avec une interface de type conteneur. Il doit être préféré aux tableaux de style C car il est plus cohérent avec d'autres conteneurs (par exemple std::vector<T>) et prend également en charge les comparaisons lexicographiques hors de la boîte.

Vittorio Romeo
la source
2
"Il faudrait écrire une sorte de comparaison lexicographique et décider ce que cela signifie pour des collections de différentes tailles." Vous pouvez simplement utiliser std::equal(via std::beginet std::endqui sont définis pour les tableaux). Dans ce cas, des tableaux de tailles différentes ne sont pas égaux.
Stu
3
Il convient de noter que pour les boucles dont la plage est un tableau, elles doivent lire la taille du tableau au moment de la compilation - c'est un peu plus subtil car (heureusement!) On n'écrit jamais le type du tableau dans cet exemple, mais cela semble beaucoup plus que la surcharge basée sur la taille.
Milo Brandt
8

La quantité d'espace allouée à un objet lorsque vous le créez dépend entièrement de son type. L'allocation dont je parle n'est pas des allocations de newou malloc, mais l'espace qui est alloué pour que vous puissiez exécuter votre constructeur et initialiser votre objet.

Si vous avez une structure définie comme (par exemple)

struct A { char a, b; }; //sizeof(A) == 2, ie an A needs 2 bytes of space

Ensuite, lorsque vous construisez l'objet:

A a{'a', 'b'};

Vous pouvez considérer le processus de construction de l'objet comme un processus:

  • Allouez 2 octets d'espace (sur la pile, mais où n'a pas d'importance pour cet exemple)
  • Exécutez le constructeur de l'objet (dans ce cas, copiez 'a'et 'b'vers l'objet)

Il est important de noter que les 2 octets d'espace nécessaires sont entièrement déterminés par le type de l'objet, les arguments de la fonction n'ont pas d'importance. Ainsi, pour un tableau, le processus est le même, sauf que maintenant la quantité d'espace nécessaire dépend du nombre d'éléments dans le tableau.

char a[] = {'a'}; //need space for 1 element
char b[] = {'a', 'b', 'c', 'd', 'e'}; //need space for 5 elements

Donc, les types de aet bdoivent refléter le fait qu'il a abesoin de suffisamment d'espace pour 1 caractère et qu'il bfaut suffisamment d'espace pour 5 caractères. Cela signifie que la taille de ces tableaux ne peut pas changer soudainement, une fois qu'un tableau à 5 éléments est créé, il s'agit toujours d'un tableau à 5 éléments. Afin d'avoir des objets de type "tableau" dont la taille peut varier, vous avez besoin d'une allocation de mémoire dynamique, que votre livre devrait couvrir à un moment donné.

SirGuy
la source
0

C'est pour une raison interne à la bibliothèque d'exécution. Si vous considérez les déclarations suivantes, par exemple:

unsigned int i;
unsigned int *iPtr;
unsigned int *iPtrArr[2];
unsigned int **iPtrHandle;

Ensuite, il devient clair quel est le problème: par exemple, l'adressage de unsigned int *doit se préoccuper de l' sizeof operatoradressage de unsigned int.

Il y a une explication plus détaillée pour le reste de ce que vous voyez ici, mais c'est en grande partie une récapitulation de ce qui a été couvert dans le langage de programmation C, 2e édition par Kernighan et Ritchie concernant le programme qui imprime le texte en langage clair du type déclaré chaîne.

CR Ward
la source