Dans notre cours C ++, ils suggèrent de ne plus utiliser de tableaux C ++ sur de nouveaux projets. Pour autant que je sache, Stroustroup lui-même suggère de ne pas utiliser de tableaux. Mais y a-t-il des différences de performances importantes?
208
int main(int argc, const std::vector<string>& argv)
Réponses:
L'utilisation de tableaux C ++ avec
new
(c'est-à-dire l'utilisation de tableaux dynamiques) doit être évitée. Il y a le problème que vous devez garder une trace de la taille, et vous devez les supprimer manuellement et faire toutes sortes de ménage.L'utilisation de tableaux sur la pile est également déconseillée car vous n'avez pas de vérification de plage, et le passage du tableau perdra toutes les informations sur sa taille (conversion de tableau en pointeur). Tu devrais utiliser
boost::array
dans ce cas, qui encapsule un tableau C ++ dans une petite classe et fournit unesize
fonction et des itérateurs pour itérer dessus.Maintenant, les tableaux std :: vector vs natifs C ++ (tirés d'Internet):
Remarque: Si vous allouez des tableaux avec
new
et allouez des objets non-classe (comme plainint
) ou des classes sans constructeur défini par l'utilisateur et que vous ne voulez pas que vos éléments soient initialisés initialement, l'utilisation denew
tableaux alloués peut présenter des avantages en termes de performances car ilstd::vector
initialise tous les éléments à valeurs par défaut (0 pour int, par exemple) sur la construction (crédit à @bernie pour me le rappeler).la source
Préambule pour les micro-optimiseurs
Rappelles toi:
(Merci à la métamorphose pour le devis complet)
N'utilisez pas un tableau C au lieu d'un vecteur (ou autre) simplement parce que vous pensez qu'il est plus rapide car il est censé être de niveau inférieur. Tu aurais tort.
Utilisez le vecteur par défaut (ou le conteneur sécurisé adapté à vos besoins), puis si votre profileur indique qu'il s'agit d'un problème, voyez si vous pouvez l'optimiser, soit en utilisant un meilleur algorithme, soit en changeant de conteneur.
Cela dit, nous pouvons revenir à la question d'origine.
Tableau statique / dynamique?
Les classes de tableaux C ++ se comportent mieux que les tableaux C de bas niveau car elles en savent beaucoup sur elles-mêmes et peuvent répondre aux questions que les tableaux C ne peuvent pas. Ils sont capables de nettoyer après eux-mêmes. Et plus important encore, ils sont généralement écrits à l'aide de modèles et / ou d'inlining, ce qui signifie que ce qui apparaît à beaucoup de code dans le débogage se résout à peu ou pas de code produit dans la version Release, ce qui signifie aucune différence avec leur concurrence intégrée moins sûre.
Dans l'ensemble, il se divise en deux catégories:
Tableaux dynamiques
Utiliser un pointeur vers un tableau malloc-ed / new-ed sera au mieux aussi rapide que la version std :: vector, et beaucoup moins sûr (voir l' article de litb ).
Utilisez donc un std :: vector.
Tableaux statiques
L'utilisation d'un tableau statique sera au mieux:
Utilisez donc un std :: array .
Mémoire non initialisée
Parfois, utiliser un
vector
au lieu d'un tampon brut entraîne un coût visible car l'vector
initialisation du tampon lors de la construction, alors que le code qu'il remplace ne l'a pas fait, comme l'a remarqué bernie by dans sa réponse .Si tel est le cas, vous pouvez le gérer en utilisant un
unique_ptr
au lieu d'unvector
ou, si le cas n'est pas exceptionnel dans votre ligne de code, écrivez en fait une classebuffer_owner
qui possédera cette mémoire et vous donnera un accès facile et sûr, y compris des bonus comme le redimensionner (en utilisantrealloc
?), ou tout ce dont vous avez besoin.la source
Les vecteurs sont des tableaux sous le capot. La performance est la même.
Un endroit où vous pouvez rencontrer un problème de performances n'est pas de dimensionner correctement le vecteur pour commencer.
Au fur et à mesure qu'un vecteur se remplit, il se redimensionne lui-même, ce qui peut impliquer une nouvelle allocation de tableau, suivie de n constructeurs de copie, suivie d'environ n appels de destructeur, suivie d'une suppression de tableau.
Si votre construction / destruction est coûteuse, vous feriez mieux de faire du vecteur la bonne taille pour commencer.
Il existe un moyen simple de le démontrer. Créez une classe simple qui montre quand elle est construite / détruite / copiée / affectée. Créez un vecteur de ces choses et commencez à les pousser à l'arrière du vecteur. Lorsque le vecteur se remplit, il y aura une cascade d'activité lorsque le vecteur se redimensionne. Réessayez ensuite avec le vecteur dimensionné au nombre d'éléments attendu. Vous verrez la différence.
la source
std::vector
sons de gcc ne sont pas conformes aux normes? Je crois que la norme exige que lavector::push_back
complexité constante soit amortie, et l'augmentation de la capacité de 1 sur chacunpush_back
va devenir n ^ 2 complexité après avoir pris en compte les reallocs. - en supposant une sorte d'augmentation exponentielle de la capacitépush_back
etinsert
, un échecreserve
entraînera au plus une augmentation constante du facteur dans les copies de contenu vectoriel. Si vous échouiez, un facteur de croissance de vecteur exponentiel de 1,5 signifierait environ 3 fois plus de copiesreserve()
.Pour répondre à quelque chose que Mehrdad a dit:
Pas vrai du tout. Les vecteurs se dégradent bien en tableaux / pointeurs si vous utilisez:
Cela fonctionne pour toutes les implémentations STL principales. Dans la prochaine norme, il devra fonctionner (même s'il fonctionne très bien aujourd'hui).
la source
&v[n] == &v[0] + n
validitén
est fournie dans la plage de taille. Le paragraphe contenant cette déclaration n'a pas changé avec C ++ 11.Vous avez encore moins de raisons d'utiliser des tableaux simples en C ++ 11.
Il existe 3 types de tableaux dans la nature, du plus rapide au plus lent, en fonction des fonctionnalités dont ils disposent (bien sûr, la qualité de la mise en œuvre peut rendre les choses très rapides même pour le cas 3 de la liste):
std::array<T, N>
dynarray
en C ++ TS après C ++ 14. En C, il y a des VLAstd::vector<T>
Pour 1. tableaux statiques simples avec un nombre fixe d'éléments, utilisez
std::array<T, N>
en C ++ 11.Pour 2. des tableaux de taille fixe spécifié lors de l' exécution, mais cela ne changera pas leur taille, il y a discussion en C ++ 14 mais il a été déplacé à un cahier des charges technique et fabriqués à partir de C ++ 14 enfin.
Pour 3.
std::vector<T>
demandera généralement de la mémoire dans le tas . Cela peut avoir des conséquences sur les performances, mais vous pouvez utiliserstd::vector<T, MyAlloc<T>>
pour améliorer la situation avec un allocateur personnalisé. L'avantage par rapport àT mytype[] = new MyType[n];
est que vous pouvez le redimensionner et qu'il ne se décomposera pas en un pointeur, comme le font les tableaux simples.Utilisez les types de bibliothèques standard mentionnés pour éviter que les tableaux ne se décomposent en pointeurs . Vous économiserez du temps de débogage et les performances sont exactement les mêmes qu'avec des tableaux simples si vous utilisez le même ensemble de fonctionnalités.
la source
Allez avec STL. Il n'y a aucune pénalité de performance. Les algorithmes sont très efficaces et ils font un bon travail pour gérer les types de détails auxquels la plupart d'entre nous ne penseraient pas.
la source
À propos de la contribution de duli .
La conclusion est que les tableaux d'entiers sont plus rapides que les vecteurs d'entiers (5 fois dans mon exemple). Cependant, les tableaux et les vecteurs sont à la même vitesse pour les données plus complexes / non alignées.
la source
STL est une bibliothèque fortement optimisée. En fait, il est même suggéré d'utiliser STL dans les jeux où des performances élevées peuvent être nécessaires. Les tableaux sont trop sujets aux erreurs pour être utilisés dans les tâches quotidiennes. Les compilateurs d'aujourd'hui sont également très intelligents et peuvent vraiment produire un excellent code avec STL. Si vous savez ce que vous faites, STL peut généralement fournir les performances nécessaires. Par exemple, en initialisant les vecteurs à la taille requise (si vous le savez depuis le début), vous pouvez essentiellement obtenir les performances du tableau. Cependant, il peut y avoir des cas où vous avez encore besoin de tableaux. Lors de l'interfaçage avec du code de bas niveau (c'est-à-dire un assemblage) ou d'anciennes bibliothèques qui nécessitent des tableaux, vous ne pourrez peut-être pas utiliser de vecteurs.
la source
vec.data()
pour les données etvec.size()
pour la taille. C'est si facile.Si vous compilez le logiciel en mode débogage, de nombreux compilateurs n'intégreront pas les fonctions d'accesseur du vecteur. Cela rendra l'implémentation du vecteur stl beaucoup plus lente dans les circonstances où les performances sont un problème. Cela facilitera également le débogage du code car vous pouvez voir dans le débogueur la quantité de mémoire allouée.
En mode optimisé, je m'attendrais à ce que le vecteur stl s'approche de l'efficacité d'un tableau. En effet, de nombreuses méthodes vectorielles sont désormais intégrées.
la source
Il y a certainement un impact sur les performances à utiliser un
std::vector
vs un tableau brut lorsque vous voulez un tampon non initialisé (par exemple à utiliser comme destination pourmemcpy()
). Anstd::vector
initialisera tous ses éléments à l'aide du constructeur par défaut. Un tableau brut ne le sera pas.La spécification c ++ pour le
std:vector
constructeur prenant uncount
argument (c'est la troisième forme) indique:Un tableau brut n'encourt pas ce coût d'initialisation.
Voir aussi Comment éviter std :: vector <> pour initialiser tous ses éléments?
la source
La différence de performances entre les deux dépend beaucoup de l'implémentation - si vous comparez un vecteur std :: mal implémenté à une implémentation de tableau optimale, le tableau gagnerait, mais le retournerait et le vecteur gagnerait ...
Tant que vous comparez des pommes avec des pommes (soit le tableau et le vecteur ont un nombre fixe d'éléments, soit les deux sont redimensionnés dynamiquement), je pense que la différence de performances est négligeable tant que vous suivez la pratique du codage STL. N'oubliez pas que l'utilisation de conteneurs C ++ standard vous permet également d'utiliser les algorithmes pré-roll qui font partie de la bibliothèque C ++ standard et la plupart d'entre eux sont susceptibles d'être plus performants que la mise en œuvre moyenne du même algorithme que vous construisez vous-même .
Cela dit, à mon humble avis, le vecteur gagne dans un scénario de débogage avec une STL de débogage, car la plupart des implémentations STL avec un mode de débogage approprié peuvent au moins mettre en évidence / signaler les erreurs typiques commises par les personnes lors de l'utilisation de conteneurs standard.
Oh, et n'oubliez pas que le tableau et le vecteur partagent la même disposition de mémoire afin que vous puissiez utiliser des vecteurs pour transmettre des données au code C ou C ++ hérité qui attend des tableaux de base. Gardez à l'esprit que la plupart des paris sont désactivés dans ce scénario, et vous avez à nouveau affaire à de la mémoire brute.
la source
std::deque
peut être utilisé.Si vous n'avez pas besoin d'ajuster dynamiquement la taille, vous avez la surcharge de mémoire pour enregistrer la capacité (un pointeur / size_t). C'est tout.
la source
Il peut y avoir un cas limite où vous avez un accès vectoriel à l'intérieur d'une fonction inline à l'intérieur d'une fonction inline, où vous êtes allé au-delà de ce que le compilateur va inline et cela forcera un appel de fonction. Ce serait si rare qu'il ne vaut pas la peine de s'inquiéter - en général, je suis d'accord avec litb .
Je suis surpris que personne n'ait encore mentionné cela - ne vous inquiétez pas des performances jusqu'à ce qu'il soit prouvé qu'elles posent problème, puis comparez.
la source
Je dirais que la principale préoccupation n'est pas la performance, mais la sécurité. Vous pouvez faire beaucoup d'erreurs avec les tableaux (pensez à redimensionner, par exemple), où un vecteur vous épargnerait beaucoup de douleur.
la source
Les vecteurs utilisent un peu plus de mémoire que les tableaux car ils contiennent la taille du tableau. Ils augmentent également la taille du disque dur des programmes et probablement l'empreinte mémoire des programmes. Ces augmentations sont minimes, mais peuvent avoir de l'importance si vous travaillez avec un système intégré. Bien que la plupart des endroits où ces différences comptent sont des endroits où vous utiliseriez C plutôt que C ++.
la source
Le test simple suivant:
Explication du test de performances du tableau C ++ vs du vecteur
contredit les conclusions de "Comparaison du code d'assembly généré pour les opérations d'indexation, de déréférencement et d'incrémentation de base sur les vecteurs et les tableaux / pointeurs."
Il doit y avoir une différence entre les tableaux et les vecteurs. Le test le dit ... essayez-le, le code est là ...
la source
Parfois, les tableaux sont en effet meilleurs que les vecteurs. Si vous manipulez toujours un ensemble d'objets de longueur fixe, les tableaux sont meilleurs. Tenez compte des extraits de code suivants:
où la version vectorielle de X est
et la version tableau de X est:
La version du tableau de main () sera plus rapide car nous évitons la surcharge de "nouveau" à chaque fois dans la boucle interne.
(Ce code a été publié par comp.lang.c ++ par moi).
la source
Si vous utilisez des vecteurs pour représenter un comportement multidimensionnel, il y a un impact sur les performances.
Les vecteurs 2D + provoquent-ils un impact sur les performances?
L'essentiel est qu'il y a une petite quantité de surcharge avec chaque sous-vecteur ayant des informations de taille, et il n'y aura pas nécessairement de sérialisation des données (comme c'est le cas avec les tableaux c multidimensionnels). Ce manque de sérialisation peut offrir des opportunités supérieures à la micro-optimisation. Si vous faites des tableaux multidimensionnels, il peut être préférable d'étendre simplement std :: vector et de lancer votre propre fonction get / set / resize bits.
la source
En supposant un tableau de longueur fixe (par exemple,
int* v = new int[1000];
vsstd::vector<int> v(1000);
, avec une taillev
fixée à 1000), la seule considération de performance qui compte vraiment (ou du moins qui m'importait lorsque j'étais dans un dilemme similaire) est la vitesse d'accès à un élément. J'ai recherché le code vectoriel de la STL, et voici ce que j'ai trouvé:Cette fonction sera très certainement intégrée par le compilateur. Donc, tant que la seule chose avec laquelle vous prévoyez de faire
v
est d'accéder à ses élémentsoperator[]
, il semble qu'il ne devrait pas y avoir vraiment de différence de performances.la source