std::vector contre std::array en C++

Quelle est la différence entre un std::vector et un std::array en C++? Quand faut-il être préféré à un autre? Quels sont les avantages et les inconvénients de chacun? Tout ce que fait mon manuel, c'est d'énumérer comment ils sont les mêmes.

227
demandé sur Martin G 2010-12-13 01:55:35

6 réponses

std::vector est une classe de template qui encapsule un tableau dynamique 1 , stocké dans le tas, qui croît et rétrécit automatiquement si des éléments sont ajoutés ou supprimés. Il fournit tous les crochets ( begin() , end() , itérateurs, etc) qui le font fonctionner très bien avec le reste de la STL. Il a également plusieurs méthodes utiles qui vous permettent d'effectuer des opérations qui sur un tableau normal serait lourd, comme l'insertion d'éléments au milieu d'un vecteur (il s'occupe de tout le travail de déplacement des éléments suivants dans les coulisses).

Puisqu'il stocke les éléments en mémoire alloués sur le tas, il a un certain overhead en ce qui concerne les tableaux statiques.

std::array est une classe de template qui encapsule un tableau de taille statique, stocké à l'intérieur de l'objet lui-même, ce qui signifie que, si vous instanciez la classe sur la pile, le tableau lui-même sera sur la pile. Sa taille doit être connue au moment de la compilation passé comme paramètre de template), et il ne peut pas croître ou rétrécir.

c'est plus limité que std::vector , mais c'est souvent plus efficace, surtout pour les petites tailles, parce qu'en pratique c'est surtout une enveloppe légère autour d'un tableau de style C. Cependant, il est plus sûr, puisque la conversion implicite en pointeur est désactivée, et il fournit une grande partie de la fonctionnalité liée à STL std::vector et des autres conteneurs, de sorte que vous pouvez l'utiliser facilement avec STL algorithms & co. Quoi qu'il en soit, pour la limite même de taille fixe il est beaucoup moins flexible que std::vector .

pour une introduction à std::array , jetez un oeil à cet article ; pour une introduction rapide à std::vector et aux opérations qui sont possibles sur elle, vous pouvez vouloir regarder à sa documentation .


  1. en fait, je pense que dans le standard ils sont décrits en termes de complexité maximale des différentes opérations (par exemple accès aléatoire en temps constant, itération sur tous les éléments en temps linéaire, ajout et suppression d'éléments à la fin en temps amorti constant, etc), mais AFAIK il n'y a pas d'autre méthode de répondre à ces exigences autre que l'utilisation d'un tableau dynamique. comme indiqué par @Lucretiel, la norme exige en fait que les éléments sont stockés de façon contiguë, donc c'est a tableau dynamique, stocké là où l'allocateur associé le place.
256
répondu Matteo Italia 2014-10-21 11:56:24

utilisant la classe std::vector<T> :

  • ...est tout aussi rapide que l'utilisation de tableaux intégrés, en supposant que vous ne faites que les choses que les tableaux intégrés vous permettent de faire (lire et écrire aux éléments existants).

  • ...redimensionne automatiquement lorsque de nouveaux éléments sont insérés.

  • ...vous permet d'insérer de nouveaux éléments au début ou au milieu du vecteur, "déplaçant" automatiquement le reste des éléments "vers le haut"( cela a-t-il un sens?). Il vous permet de supprimer des éléments n'importe où dans le std::vector , aussi, en déplaçant automatiquement le reste des éléments vers le bas.

  • ...vous permet d'effectuer une lecture de portée contrôlée avec la méthode at() (vous pouvez toujours utiliser les indexeurs [] si vous ne voulez que ce contrôle soit effectué).

Il y a deux trois principales mises en garde à l'utilisation de std::vector<T> :

  1. vous n'avez pas d'accès fiable au pointeur sous-jacent, qui peut être un problème si vous avez affaire à des fonctions de tiers qui exigent l'adresse d'un tableau.

  2. Le std::vector<bool> la classe est stupide. Il est implémenté comme un bitfield condensé, pas comme un tableau. Éviter si vous voulez un tableau de bool s!

  3. pendant l'utilisation, std::vector<T> s vont être un peu plus grand qu'un tableau C++ avec le même nombre d'éléments. C'est parce qu'ils ont besoin de garder la trace d'une petite quantité d'autres informations, telles que leur taille actuelle, et parce que chaque fois que std::vector<T> redimensionner, ils réservent plus d'espace qu'ils ont besoin. C'est à leur éviter de devoir redimensionner à chaque fois qu'un nouvel élément est inséré. Ce comportement peut être modifié en fournissant une coutume allocator , mais je n'ai jamais ressenti le besoin de le faire!


Edit: après avoir lu la réponse de Zud à la question, j'ai senti que je devais ajouter ceci:

la classe std::array<T> n'est pas la même qu'un tableau C++. std::array<T> est un enveloppement très fin autour des matrices C++, avec le primaire but de cacher le pointeur à l'utilisateur de la classe (en C++, les tableaux sont implicitement moulés comme des pointeurs, souvent à l'effet de démembrement). La classe std::array<T> conserve également sa taille (longueur), qui peut être très utile.

14
répondu ClosureCowboy 2010-12-12 23:32:34

pour souligner un point soulevé par @MatteoItalia, la différence d'efficacité est là où les données sont stockées. Mémoire tas (requis avec vector ) nécessite un appel au système pour allouer la mémoire et cela peut être coûteux si vous comptez des cycles. La mémoire de pile (possible pour array ) est virtuellement" zéro-overhead " en termes de temps, parce que la mémoire est attribuée en ajustant simplement le pointeur de pile et il est fait juste une fois à l'entrée d'une fonction. La pile évite également la mémoire fragmentation. Pour être sûr, std::array ne sera pas toujours sur la pile; cela dépend de l'endroit où vous l'attribuez, mais cela impliquera toujours une allocation de mémoire de moins du tas par rapport au vecteur. Si vous avez un

  • small" array " (under 100 elements say) - (une pile typique est d'environ 8 Mo, alors n'attribuez pas plus de quelques KO sur la pile ou moins si votre code est récursif)
  • la taille sera fixe
  • la durée de vie est dans la portée de la fonction (ou un membre de la valeur avec la même durée de vie que la classe parent)
  • vous êtes le comptage de cycles,

utilisez certainement un std::array sur un vecteur. Si l'une de ces exigences n'est pas vraie, utilisez un std::vector .

11
répondu Mark Lakata 2015-06-29 18:21:51

si vous envisagez d'utiliser des tableaux multidimensionnels, alors il y a une différence supplémentaire entre std::array et std::vector. Un tableau STD::multidimensionnel aura les éléments empaquetés en mémoire dans toutes les dimensions, tout comme un tableau de style c. Un vecteur std multidimensionnel::ne sera pas emballé dans toutes les dimensions.

compte tenu des déclarations suivantes:

int cConc[3][5];
std::array<std::array<int, 5>, 3> aConc;
int **ptrConc;      // initialized to [3][5] via new and destructed via delete
std::vector<std::vector<int>> vConc;    // initialized to [3][5]

un pointeur vers le premier élément du tableau de style c (cConc) ou le std::array (aConc) peut être itéré à travers tout le tableau en ajoutant 1 à chaque élément précédent. Ils sont serrés.

un pointeur vers le premier élément du tableau vectoriel (vConc) ou le tableau pointeur (ptrConc) ne peut être itéré qu'à travers les 5 premiers éléments (dans ce cas), et il y a ensuite 12 octets (sur mon système) de overhead pour le prochain vecteur.

cela signifie qu'un std:: vector> array initialisé sous la forme d'un tableau [3][1000] sera plus petite en mémoire qu'une initialisée sous la forme d'un tableau [1000][3], et les deux seront plus grandes en mémoire qu'un tableau std:attribué d'une manière ou d'une autre.

cela signifie aussi que vous ne pouvez pas simplement passer un tableau vecteur multidimensionnel (ou pointeur) à, disons, openGL sans tenir compte de la mémoire aérienne, mais vous pouvez naïvement passer un std multidimensionnel::tableau à openGL et le faire fonctionner.

8
répondu psimpson 2017-03-02 18:01:37

un des avantages que les vecteurs ont sur les tableaux est qu'il est possible de trouver le taille actuelle d'un vecteur en utilisant vector_name.taille (en) .

Comme vous pouvez l'imaginer, cela peut être très utile dans une variété de situations, où vous pouvez récupérer le nombre d'éléments dans le array_list facilement.

-12
répondu tech_boy 2015-08-21 09:46:06

un vecteur est une classe de conteneur alors qu'un tableau est une mémoire attribuée.

-14
répondu Saif al Harthi 2010-12-12 22:58:17