11
votes

Qui est plus rapide, accès au pointeur ou accès de référence?

Dans l'exemple de code ci-dessous, j'alloque des instances du morceau de structure. Dans les boucles pour les boucles, je tire ensuite à travers le bloc de mémoire et accédez aux différents instances en utilisant soit un pointeur, soit des références, et attribuez-leur des données aléatoires.

mais qui pour la boucle exécutera le plus rapide? Par mes connaissances, je dirais que la boucle de référence sera la plus rapide car elle ne nécessitera aucune déréférance et n'a pas accès à l'instance en mémoire. À quel point suis-je faux / droit? P>

struct Chunk {
    unsigned int a;
    float b;
    const char* c;
};

int main() {
    Chunk* pData = new Chunk[8];

    for( unsigned int i = 0; i < 8; ++i ) {
        Chunk* p = &pData[i];
        p->a = 1;
        p->b = 1.0f;
        p->c = "POINTERS";
    }

    for( unsigned int i = 0; i < 8; ++i ) {
        Chunk& r = pData[i];
        r.a = 1;
        r.b = 1.0f;
        r.c = "REFERENCES";
    }

    delete [] pData;
    return 0;
}


4 commentaires

Cela dépend de votre compilateur, je suppose, mais avec le mien, ils compilent au même code. La plupart des développeurs C ++ préfèrent les références comme un style.


N'oubliez pas qu'une référence est comme un pointeur automatiquement référencé.


@tadman pas selon la norme.


Il y a beaucoup de détails techniques quant à pourquoi ils ne sont pas identiques, sûrs, mais en termes généraux, c'est comme ça qu'ils ont tendance à se comporter. Les différences sont importantes, mais dans cet exemple, Aren ' t pertinent.


5 Réponses :


13
votes

Ils doivent être les mêmes (pas à peu près le même, mais exactement le même) avec n'importe quel compilateur non idiot. Sous la cagoule, les références sont pointeurs (sur 99% des compilateurs). Il n'y a aucune raison de toute différence.

Pedantic: la seconde boucle pourrait être plus rapide (probablement pas) car les données sont déjà dans le cache, mais c'est tout. :)


15 commentaires

Probablement un fanatique C qui aime mieux les flèches que les ampersands.


Pas 100% correct. Les références ne sont pas des pointeurs, ils ne sont pas du tout des objets. Ils pourraient être mis en œuvre par des pointeurs dans plusieurs cas, mais pas à 100%. Et le code généré pour le pointeur et pour référence pourrait différer.


N'a pas été évité, je viens de rappeler mon uppote après avoir lu toute la réponse ;-)


@ROST sur la plupart des compilateurs, ils sont mis en œuvre avec des pointeurs (mais j'ai corrigé la réponse pour refléter que ce n'est pas obligatoire). Pourtant, pouvez-vous nommer un compilateur où cela ne tient pas?


@Luchiangriggore Oui Si vous voulez dire que le pointeur est "Adresse de la mémoire", NO IF (I Widon) Pointeur est "Objet contenant une adresse mémoire".


Je n'ai pas répondu, bien que je suis enclin à le faire: Les références sont Les pointeurs sont faux. Les références sont alias et peuvent ou ne peuvent pas être des pointeurs. La sémantique est différente et la norme les traite différemment. En particulier dans le code ci-dessus, le compilateur ne fera probablement même pas de réserver de l'espace dans la pile pour la référence et il suffit de remplacer la référence avec l'objet référencé. 8.3.2 / 4 Il est indéterminé si une référence nécessite ou non un stockage (3.7). c'est pas le comportement d'un pointeur.


@Luchiangriggore Si un compilateur mettra en œuvre la référence avec un pointeur ou non dépendre de beaucoup de choses; La plupart des compilateurs utiliseront des pointeurs dans certains contextes, mais pas dans d'autres. Bien sûr, la même chose est vraie, même si vous utilisez un pointeur; Le compilateur pourrait facilement supprimer le pointeur, si Cela pourrait prouver que le pointeur n'a jamais été réinstallé.


Notez que ce n'est pas seulement le pourcentage de compilateurs, mais l'utilisation spécifique de la référence. Une référence stockée en tant que membre d'un objet doit avoir un stockage, mais la référence dans la question n'a pas besoin de prendre de la place du tout.


@ Davidrodríguez-Dribesas Vous avez manqué la partie "sous la capuche", ce qui est important.


@Luchiangriggore: Nous avons probablement une condition de race ici ... Lisez mon dernier commentaire. Sous le capot Une référence peut ou non être un pointeur, cela dépend des choses comme la durée de vie de la référence et de la portée. Deux références dans le même programme peuvent être mises en œuvre sous la hotte comme un simple alias (pas d'espace) ni un pointeur.


@ Davidrodríguez-Dribesas oui et non. La règle AS-si vous permettra au compilateur de faire à peu près la même chose avec les pointeurs qu'il le fait avec des références, fourni il peut prouver qu'ils répondent aux mêmes conditions. La différence est que le compilateur sait, sans aucune analyse, que la référence ne sera pas réititée, ne peut pas avoir son adresse prise, etc. En simple code comme ce qui précède, cela ne fait probablement aucune différence, mais dans des instances plus compliquées, L'utilisation de références au lieu des pointeurs peut aider le compilateur.


@Luchiangriggore En fait, votre deuxième paragraphe est presque certainement vrai. La deuxième boucle sera plus rapide, car les données sont déjà dans le cache. Sur simple code comme ce qui précède, il pourrait facilement être deux ou trois fois plus rapide.


@Jameskanze bien ... comme-si ... le compilateur peut réorganiser le code (ou ne générer aucun code du tout).


@Luchiangriggore Bon point. Tout compilateur décent supprimera complètement les deux boucles, car les changements d'état qu'ils n'ont aucun effet sur la production du programme. En ce qui concerne votre discussion avec David, cependant: la norme indique que les références sont pas objets, ce qui les rend très différents des pointeurs. Théoriquement. En pratique, je ne pense pas que vous puissiez dire la différence entre une référence et un pointeur qui est automatiquement déréférencé partout, mais en initialisation: une référence se comporte comme - s'il s'agissait d'un pointeur automatiquement déréférencé.


@Jameskanze Eh bien, c'est ce que je voulais dire. Vous ne pouvez pas vraiment répondre de choses comme celle-ci avec la théorie.



1
votes

Il ne devrait y avoir aucune différence de code produit par un compilateur décent.


0 commentaires

1
votes

Lorsque vous hésitez entre deux versions du code comme ceux de votre exemple, vous devez choisir celui de plus lisible. L'optimisation possible du type que vous proposez est censée être faite par le compilateur.

Le plus lisible dans votre cas est plutôt la version avec des références (en réalité, peut-être pas vraiment plus lisible, mais le consensus doit préférer l'utilisation de références car les pointeurs sont plus "dangereux").

Mais retour à l'efficacité: (s'il vous plaît si quelqu'un connaît l'assembleur, mieux arrêter de lire ou que vous risquez une attaque de rire ...) À mon avis, comme le pdata est alouoré sur le tas, le compilateur devra la compiler à l'aide de des pointeurs de toute façon. Je pense que votre raisonnement pourrait être correct si votre structure a été allouée sur la pile juste avec "Données en morceaux [8];". Mais au plus tard, lorsque les optimisations du compilateur sont sur la différence doivent être supprimées de toute façon.


3 commentaires

Sur Linux, en utilisant g ++ et clang ++, les résultats du code ci-dessus sont en fait la même, par compilateur; J'ai déterminé cela en utilisant les options -S -O3 sur deux fichiers .CPP distincts et en utilisant les commentaires de l'assemblage pour garder une trace des choses. Pour g ++, j'ai dû changer le 8 sur 100 de sorte qu'il ne dérange pas le pour boucle ... pour clang ++, j'ai eu STD :: COUT La chaîne Pour l'empêcher d'optimiser le pour boucle ...


g ++ a fait Leaq movq LEQ movq , puis dans la boucle, MOVQ , MOVL , MOVQ , addq , MOVL , Leaq , MOVL < / code>, CMPQ , jne


clang ++ a fait MOVL , puis dans la boucle, MOVL , MOVL , MOVL , addl , jne . Pour g ++ et clang ++ chacun, la sortie du pointeur et de l'ensemble de référence était la même chose.



2
votes

Je suis tenté de dire: qui se soucie? Toute différence de vitesse sera négligeable, et vous devriez choisir le plus lisible. Dans ce particulier cas, je m'attendrais à voir exactement le même code généré dans les deux Cas. Dans des cas plus compliqués, le compilateur peut ne pas être capable de déterminer plus tard dans la boucle que le pointeur n'a pas été rééléé, et peut avoir à le relire. Mais pour que cela soit le cas, vous devriez être faire assez d'autres choses que la différence ne serait pas mesurable.


3 commentaires

Merci d'avoir répondu. C'est, comme vous pouvez le constater, pas un exemple de monde réel. Je me demande simplement ce que je devrais choisir dans un scénario plus complexe.


@MichaelMancilla selon ce que vous voulez faire mieux. Généralement, référence lorsque possible, et pointeur sinon. L'utilisation de référence indique au lecteur (et au compilateur) que l'objet renvoyé ne changera pas.


"Toute différence de vitesse sera négligeable", votre cas d'utilisation n'est pas des États-Unis.



1
votes

Le temps d'exécution est presque le même mais en utilisant des références moins trépidantes.


2 commentaires

Pourriez-vous expliquer plus en détail ce que vous entendez par «moins hectic» et pourquoi le temps d'exécution serait presque le même? Voir Comment puis-je écrire une bonne réponse .


Les références ne sont que syntaxiquement mieux que les indicateurs de manière à ce qu'il soit un peu facile à comprendre et à suivre, mais les pointeurs et les références sont plutôt la même chose que ce que l'ordinateur fera réellement avec eux. Les références ne sont pas une variable contrairement aux pointeurs, ce sont des constantes. Et également, il n'existe que dans notre code source, mais le pointeur est une variable et existe en mémoire. L'utilisation de références à la place des pointeurs rend le code moins désordonné, il est donc plus facile pour moi de le déboguer, donc pour moi d'utiliser des références à la place des pointeurs est moins trépidante.