Pour donner aux fonctions, la possibilité de modifier le vecteur, je ne peux pas faire mais je dois faire: p> (comme les réponses de mon autre question soulignée) p> Je vais faire un enfer beaucoup d'appels vers y a-t-il une option différente pour moi? Puis-je utiliser des pointeurs d'une manière ou d'une autre? P> li>
ul> Quand il devient sérieux, il y aura des milliers d'appels vers
myvec.at () code> alors. À quelle vitesse est-il, comparé au premier exemple en utilisant une variable pour stocker le résultat? P> LI>
myvec.at () code> par seconde. Donc, chaque petit mangeur de performance est important. P> p>
9 Réponses :
opérateur [] peut être plus rapide que Vous pouvez faire à code>, car il n'est pas nécessaire de faire la vérification des limites.
curr code> une référence pour faire ce que vous Vous voulez. P>
MyClass & curr = myvec.at(i);
Vous pouvez utiliser une référence: la fonction de membre code> à code> Les limites vérifient pour s'assurer que l'argument est dans la taille du vecteur < / code>. Le profilage n'est qu'un moyen de savoir exactement combien plus lentement est comparé à
opérateur [] code>. En utilisant une référence ici vous permet de faire la recherche une fois de la recherche, puis d'utiliser le résultat dans d'autres endroits. Et vous pouvez en faire une référence à-
const code> si vous souhaitez vous protéger de la valeur de modification accidentelle de la valeur. P> p>
Dépend de quoi "donner des fonctions la possibilité de modifier le vecteur" signifie. Certaines modifications de vecteur invalident les références - tout ce qui provoque la réaffectation.
@Steve, c'est un bon point. Je suppose que l'OP modifie valeurs i> dans le vecteur basé sur le code exemple donné. Si les fonctions peuvent modifier le vecteur lui-même, nous aurons besoin d'une approche différente.
Lorsque la performance est un problème, il n'y a pas de substitut au profilage. Les capacités d'optimisation des compilateurs changent de la version à la version, et minuscules altérations insignifiantes du code source peuvent modifier considérablement la performance résultante. P>
Personne ne peut répondre à cette question, mais vous-même: créer un harnais de test et lancer plusieurs algorithmes et voir ce que vous obtenez. P>
ps. Si la performance est vraiment un problème, j'ai eu une augmentation du facteur 10 augmentation de la vitesse d'un décodeur PNG en supprimant les vecteurs et en les remplaçant avec des matrices brutes. Encore une fois, c'était pour Visual Studio 6. Je ne prétends pas que la substitution de la matrice brute vous donnera une amélioration du facteur 10, mais c'est quelque chose à essayer. P>
Je ne sais pas à propos de VS6 (heureusement, j'ai pu utiliser GCC à l'époque), mais une incréments de vitesse de dix vitesses ressemble à une grande différence. Utilisez-vous les mêmes algorithmes dans les deux cas? La taille de vecteur a-t-elle été allongée dans la mise en œuvre? La mise en œuvre actuelle d'un vecteur dans g ++ contient trois pointeurs, à commencer () code>,
fin () code> et
commence () + capacité code>, sauf si vous activez Itérateurs vérifiés, les opérations sur un vecteur sont aussi rapides que les opérations sur les données brutes.
L'algorithme était pareil. Nous venons de modifier les vecteurs d'octets en matrices brutes d'octets. Les fonctions ont été modifiées pour prendre des pointeurs et les entiers nécessaires étant la taille de la matrice. Certaines boucles ont été déployées dans des memcpy.
La complexité de Vous pouvez utiliser Dans tous les cas, le vecteur est spécialement conçu pour un accès permanent performant à l'un de ses éléments. Donc, cela devrait être le moindre de vos soucis. P> à () code> est constante, c'est-à-dire en pratique, cela signifie qu'il doit être conçu pour ne pas avoir de pénalité de performance pertinente. P>
[] code>, qui est également une complexité constante, mais ne vérifie pas les limites. Cela équivaudrait à utiliser l'arithmétique du pointeur et, donc potentiellement un peu em> plus vite que le premier. P>
La raison pour laquelle le premier ne fonctionne pas est que vous ne définissez pas un pointeur ou un itérateur à l'adresse de la variable ith. Au lieu de cela, vous réglez cur, égal à la valeur de la variable, puis modifiant. Je suppose que Dothis et Dothat sont des références.
Faites ceci: P>
MyObject& curr = myvec.at( i );
options que je vois, à peu près Honnêtement, ce que vous devriez faire est de jouer avec les quatre approches différentes et utilisez simplement celui qui produit le code le plus facile à comprendre. Dans la plupart des cas, nous sommes heureux de sacrifier quelques cycles de machine pour le code qui est plus facile pour les êtres humains à entretenir. P>
[] code> au lieu de
at () code>. li>
at () code> une fois et enregistrez-le dans une référence (voir la réponse de Kristo ci-dessus). Li>
de mes propres tests avec un code similaire (compilé sous GCC et Linux), Utilisation d'une référence, comme Kristo a déclaré , vous permet que engendrer les limites vérifiant la tête une fois. p>
Ignorer la vérification des limites et la manipulation des exceptions des frais généraux, les deux Comme Chris Becke dit, cependant, il n'y a pas de substitut au profilage. P> opérateur [] code> peut être sensiblement plus rapide que
à code>, pas à cause de la vérification des limites, mais à cause des frais généraux de la manipulation des exceptions. Remplacer
à code> (qui jette une exception sur les limites) avec mes propres limites vérifiant qui a augmenté un Aster sur des limites inutiles a donné une amélioration mesurable. P>
opérateur [] code> et
au code> doivent être optimisés à l'accès à une gamme directe ou à un accès direct via le pointeur. P>
En fait, des exceptions déclenchantes sont généralement lentes et la vérification ne sont pas nécessairement trop lentes.
@Martin: Cela dépend beaucoup de la mise en œuvre. En raison de quelques-uns, c'est la pile de détente qui coûte cher, pas le "déclenchement" (lancer)
@Msalters - Oui, mais le test n'est pas nécessairement cher si l'exception n'est pas exceptionnelle.
Les vecteurs sont les plus adaptés à la vitesse d'accès. L'accès à un élément aléatoire dans un vecteur est de complexité O (1) par rapport à O (n) pour les listes de liaison générales et o (log n) pour les arbres de liaison. P>
Cependant, cette question est mal placée car la réponse à votre autre question vous a égaré en n'expliquant pas comment corriger votre problème d'origine en utilisant une référence. P>
Si c'est le cas, que vous chargez un vecteur, procédez-la sans ajouter ou supprimer plus d'éléments, puis envisagez d'obtenir un pointeur sur la matrice sous-jacente et utilisez des opérations de réseau sur cela pour «éviter le surcharge de vecteur». . p>
Si vous ajoutez ou supprimez des éléments dans votre traitement, cela n'est pas sûr de le faire, car la matrice sous-jacente peut être déplacée à tout moment du vecteur lui-même. P>
Outre les considérations de performance, demandez-vous ce que vous obtenez en utilisant
at () code> plutôt que
[] code>. La vérification des limites sur les indices est agréable pour le débogage mais
[] code> aussi i> est-ce lorsque vous compilez en mode de débogage, et en utilisant
à () code> au lieu de < Code> [] code> n'est pas un substitut de l'écriture du code correct, et c'est redondant si le code est déjà correct.
@ Unicorn à nez rouge: Tous les compilateurs Vérifiez
[] code> en mode de débogage.
@Brian: Malheureusement, c'est vrai. Et tu sais quoi? Que suce b>. Mais heureusement, cela peut être réparé en installant une version alternative de la bibliothèque standard - par exemple stlport: stlport.org a >.
@ Licorne à nez rouge: Non seulement le commentaire de Brian est correct, mais le test en mode de débogage ne trouve pas tous les problèmes. Il pourrait bien valoir la peine d'utiliser
.at () code> au lieu de
[] code> dans le code de production, en fonction de beaucoup de choses.
@David: Je suis en désaccord. Je suis I> d'accord pour dire qu'il peut être bénéfique d'avoir un système d'exécution vérifié (comme dans Java ou .NET). Mais je ne suis pas d'accord que changer les itérateurs et
[] code> pour une variante ostensiblement sûre est bonne. Personne n'atteint
at () code> erreurs d'exécution quand même et les personnes qui do i> saisent l'erreur peuvent aussi bien utiliser
[] code> et vérifier explicitement un index valide à l'avance. . Le seul avantage de
at () code> sur
[] code> est qu'un programme de buggy s'écrasera au lieu de travailler sur une mémoire invalide. Si vous préférez que (ce qui est parfaitement raisonnable), utilisez un système d'exécution qui donne le comportement souhaité ...
(suite) et remarquez que la norme C ++ est absolument Permet i> un tel système d'exécution vérifié. Rien ne parle contre la fabrication
[] code> une opération vérifiée.
Les gens attrapent
at () code> erreurs et ceci est souvent préférable aux vérifications manuelles avant d'appeler
opérateur [] code> sur chaque site d'appel. Le point est que C ++ vous donne le choix. Si vous avez besoin d'une vitesse, vous utilisez
opérateur [] code>.
Crashing de manière définie est Loin i> meilleur comportement que de piétinement dans une mémoire aléatoire. Oui, cela pourrait être gênant, mais cela empêche toutes sortes d'attaques dans le code de la sécurité-critique. Pour désquier Ben Franklin, «ceux qui peuvent abandonner la sécurité essentielle pour obtenir une petite vitesse temporaire, ne méritent ni la sécurité ni la rapidité.»
Pour vous citer: «Ils veulent que Java sachent où le trouver».