En utilisant des tableaux ou des vecteurs std :: en C ++, quel est l'écart de performances?

208

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?

tunnuz
la source
2
Pourquoi pensez-vous qu'il y a un écart de performance.
Martin York
99
Parce que généralement, avec de meilleures fonctionnalités, les performances sont les pires.
tunnuz
19
Je suis d'accord sur l'optimisation prématurée, mais choisir la meilleure méthode de stockage à l'avance a beaucoup de sens. Souvent, dans le monde réel, le code doit être expédié et le prochain produit développé et l'étape d'optimisation ne se produit jamais.
Ant
132
je souhaite que les gens cessent de crier "optimisation prématurée!" chaque fois que quelqu'un pose une question simple liée à la performance! répondez à la question et ne présumez pas simplement prématurément que les gens font quoi que ce soit prématurément.
d7samurai
4
@ d7samaurai: d'accord, je n'ai encore vu personne essayerint main(int argc, const std::vector<string>& argv)
Mark K Cowan

Réponses:

189

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 utiliserboost::array dans ce cas, qui encapsule un tableau C ++ dans une petite classe et fournit une sizefonction et des itérateurs pour itérer dessus.

Maintenant, les tableaux std :: vector vs natifs C ++ (tirés d'Internet):

// Comparison of assembly code generated for basic indexing, dereferencing, 
// and increment operations on vectors and arrays/pointers.

// Assembly code was generated by gcc 4.1.0 invoked with  g++ -O3 -S  on a 
// x86_64-suse-linux machine.

#include <vector>

struct S
{
  int padding;

  std::vector<int> v;
  int * p;
  std::vector<int>::iterator i;
};

int pointer_index (S & s) { return s.p[3]; }
  // movq    32(%rdi), %rax
  // movl    12(%rax), %eax
  // ret

int vector_index (S & s) { return s.v[3]; }
  // movq    8(%rdi), %rax
  // movl    12(%rax), %eax
  // ret

// Conclusion: Indexing a vector is the same damn thing as indexing a pointer.

int pointer_deref (S & s) { return *s.p; }
  // movq    32(%rdi), %rax
  // movl    (%rax), %eax
  // ret

int iterator_deref (S & s) { return *s.i; }
  // movq    40(%rdi), %rax
  // movl    (%rax), %eax
  // ret

// Conclusion: Dereferencing a vector iterator is the same damn thing 
// as dereferencing a pointer.

void pointer_increment (S & s) { ++s.p; }
  // addq    $4, 32(%rdi)
  // ret

void iterator_increment (S & s) { ++s.i; }
  // addq    $4, 40(%rdi)
  // ret

// Conclusion: Incrementing a vector iterator is the same damn thing as 
// incrementing a pointer.

Remarque: Si vous allouez des tableaux avec newet allouez des objets non-classe (comme plain int) 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 de newtableaux alloués peut présenter des avantages en termes de performances car il std::vectorinitialise tous les éléments à valeurs par défaut (0 pour int, par exemple) sur la construction (crédit à @bernie pour me le rappeler).

Johannes Schaub - litb
la source
77
Qui a inventé la putain de syntaxe AT&T? Seulement si je savais ... :)
Mehrdad Afshari
4
Ce n'est pas vrai pour le compilateur Visual C ++. Mais pour GCC c'est le cas.
toto
5
Le point dans ma réponse est que le vecteur n'ont à être plus lent que correponding opérations de pointeur. Bien sûr, cela peut être (facile à réaliser en activant également le mode de débogage) :)
Johannes Schaub - litb
18
+1 pour "L'indexation d'un vecteur est la même chose que l'indexation d'un pointeur." et pour les autres conclusions également.
Nawaz
3
@ Piotr99 Je ne vais pas discuter avec vous, mais lorsque vous apprenez à assembler après avoir appris des langages de niveau supérieur, la syntaxe Intel est beaucoup plus logique que certaines versions inversées, préfixées (nombres), suffixées (instructions) et obscures (accès à la mémoire) ) nature de la syntaxe AT&T.
Cole Johnson
73

Préambule pour les micro-optimiseurs

Rappelles toi:

"Les programmeurs perdent énormément de temps à penser ou à s'inquiéter de la vitesse des parties non critiques de leurs programmes, et ces tentatives d'efficacité ont en fait un fort impact négatif lorsque le débogage et la maintenance sont envisagés. Nous devons oublier les petites économies, par exemple 97% du temps: l' optimisation prématurée est la racine de tous les maux. Pourtant, nous ne devons pas laisser passer nos opportunités dans ces 3% critiques ".

(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:

  • aussi rapide que la version std :: array
  • et beaucoup moins sûr.

Utilisez donc un std :: array .

Mémoire non initialisée

Parfois, utiliser un vectorau lieu d'un tampon brut entraîne un coût visible car l' vectorinitialisation 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_ptrau lieu d'un vectorou, si le cas n'est pas exceptionnel dans votre ligne de code, écrivez en fait une classe buffer_ownerqui possédera cette mémoire et vous donnera un accès facile et sûr, y compris des bonus comme le redimensionner (en utilisant realloc?), ou tout ce dont vous avez besoin.

paercebal
la source
1
Merci d'avoir également adressé les tableaux statiques - std :: vector est inutile si vous n'êtes pas autorisé à allouer dynamiquement de la mémoire pour des raisons de performances.
Tom
10
Lorsque vous dites "Utiliser un tableau statique sera au mieux aussi rapide que la version boost :: array", cela montre à quel point vous êtes biaisé. Ce devrait être l'autre, Boost: array peut être au mieux rapide comme des tableaux statiques.
toto
3
@toto: C'est un malentendu: vous devriez le lire comme "L'utilisation d'un tableau statique sera au mieux ((aussi rapide que la version boost :: array) && (beaucoup moins sûr))". Je vais modifier le message pour clarifier cela. Au fait, merci pour le bénéfice du doute.
paercebal
1
qu'en est-il de std :: array?
paulm
4
Toujours montrer le devis complet. "Les programmeurs perdent énormément de temps à penser ou à s'inquiéter de la vitesse des parties non critiques de leurs programmes, et ces tentatives d'efficacité ont en fait un fort impact négatif lorsque le débogage et la maintenance sont envisagés. Nous devons oublier les petites économies, par exemple 97% du temps: l'optimisation prématurée est la racine de tous les maux. Pourtant, nous ne devons pas laisser passer nos opportunités dans ces 3% critiques. " Sinon, cela devient un extrait sonore insignifiant.
métamorphose
32

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.

EvilTeach
la source
4
Penderie: la performance a le même gros O. std :: vector fait un peu de comptabilité, ce qui coûte probablement un peu de temps. OTOH, vous finissez par faire la même comptabilité lorsque vous lancez vos propres tableaux dynamiques.
dmckee --- chaton ex-modérateur
Oui je comprends. Le but de sa question était, cependant, quelles étaient les différences de performances ... J'ai essayé de répondre à cela.
EvilTeach
Le std :: vector de Gcc augmente en effet la capacité un par un si vous appelez push_back.
bjhend
3
@bjhend Alors les std::vectorsons de gcc ne sont pas conformes aux normes? Je crois que la norme exige que la vector::push_backcomplexité constante soit amortie, et l'augmentation de la capacité de 1 sur chacun push_backva devenir n ^ 2 complexité après avoir pris en compte les reallocs. - en supposant une sorte d'augmentation exponentielle de la capacité push_backet insert, un échec reserveentraî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 copies reserve().
Yakk - Adam Nevraumont
3
@bjhend vous vous trompez. La norme interdit la croissance exponentielle: le paragraphe 23.2.3, paragraphe 16, dit: "Le tableau 101 répertorie les opérations qui sont fournies pour certains types de conteneurs de séquence mais pas pour d'autres. Une mise en œuvre doit fournir ces opérations pour tous les types de conteneurs indiqués dans la colonne" conteneur ", et les met en œuvre de manière à prendre un temps constant amorti. " (le tableau 101 est celui qui contient push_back). Veuillez maintenant arrêter de diffuser le FUD. Aucune mise en œuvre traditionnelle ne viole cette exigence. La bibliothèque C ++ standard de Microsoft croît avec un facteur 1,5x et GCC grandit avec un facteur 2x.
R. Martinho Fernandes
27

Pour répondre à quelque chose que Mehrdad a dit:

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.

Pas vrai du tout. Les vecteurs se dégradent bien en tableaux / pointeurs si vous utilisez:

vector<double> vector;
vector.push_back(42);

double *array = &(*vector.begin());

// pass the array to whatever low-level code you have

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).

Frank Krueger
la source
1
La norme actuelle ne dit rien de tel. Il est implicite et il est implémenté en tant que stockage continu. Mais la norme dit simplement qu'il s'agit d'un conteneur à accès aléatoire (utilisant des itérateurs). La prochaine norme sera explicite.
Frank Krueger
1
& * v.begin () applique simplement l'opérateur & au résultat du déréférencement de l'itérateur. Le dé-référencement peut retourner N'IMPORTE QUEL type. L'utilisation de l'opérateur address-of peut à nouveau retourner N'IMPORTE QUEL type. La norme ne définit pas cela comme un pointeur dans une zone de mémoire contiguë.
Frank Krueger
15
Le texte original de 1998 de la norme ne l'exigeait certes pas, mais il y avait un addendum en 2003 qui traitait de cela, donc il est vraiment couvert par la norme. herbsutter.wordpress.com/2008/04/07/…
Nemanja Trifunovic
2
C ++ 03 indique explicitement que la &v[n] == &v[0] + nvalidité nest fournie dans la plage de taille. Le paragraphe contenant cette déclaration n'a pas changé avec C ++ 11.
bjhend
2
pourquoi ne pas simplement utiliser std :: vector :: data ()?
paulm
15

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):

  1. Statique avec une taille connue au moment de la compilation. ---std::array<T, N>
  2. Dynamique avec une taille connue au moment de l'exécution et jamais redimensionnée. L'optimisation typique ici est que si le tableau peut être alloué directement dans la pile. - Non disponible . Peut êtredynarray en C ++ TS après C ++ 14. En C, il y a des VLA
  3. Dynamique et redimensionnable à l'exécution. ---std::vector<T>

Pour 1. tableaux statiques simples avec un nombre fixe d'éléments, utilisezstd::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 utiliser std::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.

Germán Diago
la source
2
std :: dynarray .Après avoir examiné les commentaires des organismes nationaux sur n3690, ce composant de bibliothèque a été rejeté du document de travail C ++ 14 dans une spécification technique distincte. Ce conteneur ne fait pas partie du projet C ++ 14 à partir de n3797. de en.cppreference.com/w/cpp/container/dynarray
Mohamed El-Nakib
1
très bonne réponse. bref et résumant, mais plus de détails que tout autre.
Mohamed El-Nakib
6

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.

John D. Cook
la source
6

À 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.

lalebarde
la source
5

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.

Mehrdad Afshari
la source
4
étant donné que le vecteur est contigu, il est toujours assez facile de s'interfacer avec les bibliothèques qui nécessitent des tableaux.
Greg Rogers
Oui, mais si vous voulez jouer avec les trucs internes du vecteur, il y aurait moins d'avantages à utiliser un vecteur. Soit dit en passant, le mot clé était «peut-être pas».
Mehrdad Afshari
3
je ne connais qu'un seul cas où les vecteurs ne peuvent pas être utilisés: si la taille est 0. alors & a [0] ou & * a.begin () ne fonctionnera pas. c ++ 1x corrigera cela en introduisant une fonction a.data () qui retourne le tampon interne en gardant les éléments
Johannes Schaub - litb
Le scénario spécifique dans mon esprit quand j'ai écrit que c'était des tableaux basés sur la pile.
Mehrdad Afshari
1
Vecteur d'interface ou tout conteneur contigu avec C: vec.data()pour les données et vec.size()pour la taille. C'est si facile.
Germán Diago
3

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
C'est important à mentionner. Le profilage du débogage STL est très, très lent. Et c'est l'une des raisons pour lesquelles les gens pensent que la STL est lente.
Erik Aronesty
3

Il y a certainement un impact sur les performances à utiliser un std::vectorvs un tableau brut lorsque vous voulez un tampon non initialisé (par exemple à utiliser comme destination pour memcpy()). An std::vectorinitialisera 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:vectorconstructeur prenant un countargument (c'est la troisième forme) indique:

`Construit un nouveau conteneur à partir d'une variété de sources de données, en utilisant éventuellement un allocateur fourni par l'utilisateur alloc.

3) Construit le conteneur avec le nombre d'instances de T. insérées par défaut. Aucune copie n'est effectuée.

Complexité

2-3) Linéaire en nombre

Un tableau brut n'encourt pas ce coût d'initialisation.

Voir aussi Comment éviter std :: vector <> pour initialiser tous ses éléments?

bernie
la source
2

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.

Timo Geusch
la source
1
Je pense que pour répondre aux exigences de performance (O (1) et insertions lookups), vous presque avez à mettre en œuvre std :: vector <> à l' aide des tableaux de dynamiques. C'est certainement la façon évidente de le faire.
dmckee --- chaton ex-modérateur
Non seulement les exigences de performances, mais aussi l'exigence que le stockage soit contigu. Une mauvaise implémentation vectorielle mettra trop de couches d'indirection entre le tableau et l'API. Une bonne implémentation vectorielle permettra le code en ligne, SIMD utilisé sur les boucles, etc.
Max Lybbert
Une mauvaise implémentation de vecteur telle que décrite ne serait pas conforme à la norme. Si vous souhaitez une indirection, std::dequepeut être utilisé.
Phil1970
1

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.

Greg Rogers
la source
1

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.

Mark Ransom
la source
1

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.

Gabriel Isenberg
la source
1

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 ++.

Brian
la source
2
Si cela est important, vous n'utilisez évidemment pas de tableaux de taille dynamique, et en tant que tels, vos tableaux n'ont pas besoin de changer de taille. (S'ils le faisaient, vous stockeriez la taille d'une manière ou d'une autre). Par conséquent, vous pourriez aussi bien utiliser boost :: array, sauf erreur de ma part - et qu'est-ce qui vous fait dire que cela doit "stocker la taille" quelque part?
Arafangion
1

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à ...

Hamed100101
la source
1

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:

int main() {
int v[3];
v[0]=1; v[1]=2;v[2]=3;
int sum;
int starttime=time(NULL);
cout << starttime << endl;
for (int i=0;i<50000;i++)
for (int j=0;j<10000;j++) {
X x(v);
sum+=x.first();
}
int endtime=time(NULL);
cout << endtime << endl;
cout << endtime - starttime << endl;

}

où la version vectorielle de X est

class X {
vector<int> vec;
public:
X(const vector<int>& v) {vec = v;}
int first() { return vec[0];}
};

et la version tableau de X est:

class X {
int f[3];

public:
X(int a[]) {f[0]=a[0]; f[1]=a[1];f[2]=a[2];}
int first() { return f[0];}
};

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).

duli
la source
1

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.

Seph Reed
la source
0

En supposant un tableau de longueur fixe (par exemple, int* v = new int[1000];vs std::vector<int> v(1000);, avec une taille vfixé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é:

const_reference
operator[](size_type __n) const
{ return *(this->_M_impl._M_start + __n); }

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 vest d'accéder à ses éléments operator[], il semble qu'il ne devrait pas y avoir vraiment de différence de performances.

Subh_b
la source