IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Différence Pointeur Référence.


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 048
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 048
    Par défaut Différence Pointeur Référence.
    Bonjour à tous,

    Durant plusieurs échange sur ce forum concernant le faite de passer en référence, des objets ou des références, j'attire l'attention sur le faite que un accès via un pointeur est plus lent qu'un accès via une référence.
    Je ne viens pas ouvrir ce poste pour être cartésien en disant que la référence est la solution ultime, mais le but est de prouvé que le pointeur n'est pas la solutions à prendre si nous avons le choix.
    Vous trouverez-ci joint la code machine avec les informations suivantes:
    - debug visual studio 2008.
    - Release visual studio 2008 avec information de debug
    - Optimisation complète ( /0x )

    PS: Si quelqu'un sait comment observer le code machine des instanciations statiques en release ça m'arrangerais, je n'ai que le détail des instanciations dynamiques

    Le test-code, j'ai réalisé une classe MonInt, contenant un int, et un accesseur pour le int:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    struct MonInt
    {
        int i_;
        MonInt():i_(){}
        MonInt(int i):i_(i){}
        MonInt(const MonInt& i)
            :i_(i.i_)
        {}
        int Geti(){ return i_; }
    };
    Mon test s'interroge sur plusieurs aspects:

    1- La création
    2- L'accès via déréférencement( * ou ->) ou via une référence (.)
    3- Le passage par Pointeur ou référence


    Je vais essayer d'être le plus pragmatique possible. Et de présenter les résultats de façon simple.


    1- La création

    La création est sans aucun doute plus rapide de façon statique, mais le but du test n'est pas ici, je le présente quand même pour ceux qui voudrait comprendre la réel différence.

    Instanciation dynamique


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    MonInt* monIntPtr = new MonInt(33);
     
    ---------------------------------------------
     
    01261126  push        4    
    01261128  call        operator new (126152Ah) 
    0126112D  add         esp,4 
    01261130  mov         dword ptr [ebp-2Ch],eax 
    01261133  mov         dword ptr [ebp-4],0 
    0126113A  cmp         dword ptr [ebp-2Ch],0 
    0126113E  je          main+6Fh (126114Fh) 
    01261140  push        21h  
    01261142  mov         ecx,dword ptr [ebp-2Ch] 
    01261145  call        MonInt::MonInt (1261005h) 
    0126114A  mov         dword ptr [ebp-30h],eax 
    0126114D  jmp         main+76h (1261156h) 
    0126114F  mov         dword ptr [ebp-30h],0 
    01261156  mov         eax,dword ptr [ebp-30h] 
    01261159  mov         dword ptr [ebp-28h],eax 
    0126115C  mov         dword ptr [ebp-4],0FFFFFFFFh 
    01261163  mov         ecx,dword ptr [ebp-28h] 
    01261166  mov         dword ptr [ebp-10h],ecx
    On observe déjà une foule d'instructions. Pour l'opérateur new, pour la construction de la classe.

    Instanciation statique

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    MonInt monIntRef(33);
     
    ---------------------------------------------
     
    01261169  push        21h  
    0126116B  lea         ecx,[ebp-18h] 
    0126116E  call        MonInt::MonInt (1261005h)
    Sans aucun doute, la création d'un variable statique est plus performante qu'une création dynamique.

    Résultat(Debug):
    - Dynamique : 18 instructions
    - Statique : 3 instructions

    Résultat(Release avec informations Debug):
    - Dynamique : 9 instructions
    - Statique : Aucun résultat


    2- L'accès via déréférencement( * ou ->) ou via une référence (.)

    C'est donc ici que l'on rentre dans le vive du sujet. Plusieurs fois j'ai lu que la différence pointeur et référence n'était que d'un point de vue esthétique ou conceptuel. Hors selon mes tests, il apparait qu'il y ai une instruction supplémentaire. Certains diront que les ordinateurs sont plus rapides aujourd'hui ça n'a aucun intérêt! Pour un logiciel de comptabilité pour la propriétaire d'un boulangerie sans aucun doute. Mais dans des milieux ou le moindre coup est prenable, non pas parce que on cherche la nano seconde sur une instruction, mais parce on cherche la nanoseconde * x présence dans le code ( huge code soit dit en passant ). Les jeux high-tech sur téléphone portable, les consoles de salon, voir les systèmes embarqués ( je ne connais pas ce milieu mais ça ce rapproche des consoles , voir c'est identique ).

    Ce test sont réalisé avec :
    - Release avec informations Debug sous Visual Studio 2008.
    - Optimisation complète ( /0x )

    accès via déréférencement( * ou ->)

    Accès via l'opérateur *

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    std::cout << (*monIntPtr).i_;
     
    ---------------------------------------------
     
    0108101B  mov         eax,dword ptr [esi] 
    0108101D  mov         ecx,dword ptr [__imp_std::cout (108203Ch)] 
    01081023  push        eax  
    01081024  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (1082038h)]
    Ici nous observons 4 instructions ( avec l'appel de cout , apparenté à l'appel d'une fonction operator<<() )

    Accès via l'opérateur ->

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    std::cout << monIntPtr->i_;
     
    ---------------------------------------------
     
    01081038  mov         ecx,dword ptr [esi] 
    0108103A  push        ecx  
    0108103B  mov         ecx,dword ptr [__imp_std::cout (108203Ch)] 
    01081041  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (1082038h)]
    Ici nous observons 4 instructions ( avec l'appel de cout , apparenté à l'appel d'une fonction operator<<() ). Identique à l'appel avec l'opérateur * à ceci prêt que deux instructions sont inversées. Si quelqu'un à une explication?

    accès via une référence (.)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    std::cout << monIntRef.i_;
     
    ---------------------------------------------
     
    0108102A  mov         ecx,dword ptr [__imp_std::cout (108203Ch)] 
    01081030  push        21h  
    01081032  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (1082038h)]
    Ici nous observons 3 instructions ( avec l'appel de cout , apparenté à l'appel d'une fonction operator<<() ). Donc une instruction de moins que l'accès via pointeur.

    Résultat(Release avec informations Debug):
    - Accès via déréférencement (* ou ->) : 4 instructions ( avec un appel de fonction operator<<() )
    - Accès via une référence ( . ): 3 instructions ( avec un appel de fonction operator<<() )


    3- Le passage par Pointeur ou référence


    La ou ça deviens intéressant, c'est de ce demander si l'on dois passer par pointeur ou par référence. Hormis le faite que le pointeur peut ne pas être initialisé, par ça j'entends pointer sur l'adresse 0x00000000, et peut contrairement à la référence, référencer une nouvelle zone mémoire. La différence entre les deux reste subtile. Pour réaliser les tests, j'ai écris deux fonctions. En voici les définitions:

    Passage par pointeur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void fooPtr(MonInt* monInt)
    {
        std::cout << monInt->Geti();
    }
    Passage par référence:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void fooRef(MonInt& monInt)
    {
        std::cout << monInt.Geti();
    }
    J'ai volontairement mis les std::cout pour remettre en avant cette différence.

    En considérant les variables créées comme suit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    MonInt* monIntPtr = new MonInt(33);
    MonInt monIntRef(33);
    Voici les résultats aux l'appel des fonctions:

    Passage par pointeur:

    Passage d'un pointeur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    fooPtr(monIntPtr);
     
    ---------------------------------------------
     
    00E51047  mov         edx,dword ptr [esi] 
    00E51049  mov         ecx,dword ptr [__imp_std::cout (0E5203Ch)] 
    00E5104F  push        edx  
    00E51050  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0E52038h)]
    La fonction prenant en paramètre un pointeur, lui passant un pointeur. Ne consomme rien.

    Passage d'une référence:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    fooPtr(&monIntRef);
     
    ---------------------------------------------
     
    00E51056  mov         ecx,dword ptr [__imp_std::cout (0E5203Ch)] 
    00E5105C  push        21h  
    00E5105E  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0E52038h)]
    La fonction prenant en paramètre un pointeur, lui passant un référence sur un objet de la pile. Ne consomme rien.

    Passage par référence:

    Passage d'un objet sur le tas via déréférencement:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    fooRef(*monIntPtr);
     
     ---------------------------------------------
     
    00E51064  mov         eax,dword ptr [esi] 
    00E51066  mov         ecx,dword ptr [__imp_std::cout (0E5203Ch)] 
    00E5106C  push        eax  
    00E5106D  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0E52038h)]
    La fonction prenant en paramètre une référence, lui passant un déréférencement d'un objet sur le tas. Ne consomme rien.

    Passage d'un objet sur la pile:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    fooRef(monIntRef);
     
      ---------------------------------------------
     
    00E51073  mov         ecx,dword ptr [__imp_std::cout (0E5203Ch)] 
    00E51079  push        21h  
    00E5107B  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0E52038h)]
    La fonction prenant en paramètre une référence, lui passant un un objet sur le pile. Ne consomme rien.

    Résultat(Release avec informations Debug):
    - Passage par pointeur : 0 instructions
    - Passage par référence : 0 instructions

    Après avoir observé ces résultats, nous sommes en mesure de se demander qu'elle est le but alors d'un test pareil? Sa n'a pas de sens!
    Et pourtant si, le but est de comprendre que ce n'est pas le type de passage qui est important mais ce qu'il en découle. Nous avons observé que l'accès à des éléments via un pointeur (dynamique/tas) consomme une instruction supplémentaire que l'accès via une référence (statique/pile). Chaque consultation viendra ajouter une instruction. Et avec une hiérarchie plus profonde dans les classes, avec les boucles etc... Notre simple passage par pointeur viens de rajouter plusieurs centaines d'instructions! Des instructions qui nous aurais été utiles pour faire autres choses.

    Je répète encore une fois que je ne dénigre pas le pointeur, je met en avant ce qu'il coûte de part son utilisation excessive et inutile.

    Si il y a des critiques, des avis, des commentaires, des ajouts, ou des reformulations de mes propos, je suis là pour apprendre aussi

    Merci de votre lecture.

  2. #2
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Je n'ai pas encore tout lu, mais je tiens à te rappeler qu'une référence se comporte différemment selon là où elle est et ce qu'elle référence:
    • Un paramètre référence, c'est comme un pointeur déguisé. Le code généré est rigoureusement le même.
    • Pour une référence sur le déréférencement d'un pointeur, je n'ai pas testé, mais c'est probablement pareil aussi.
    • Une référence en variable locale sur cette même variable locale, c'est un alias: Quand on y accède, le compilo génère le même code que pour accéder à la variable locale elle-même.

    À la lumière de ceci, il n'y a pas vraiment de considération de performance entre pointeurs et références (hormis peut-être dans le troisième cas, si la référence ne peut pas être carrément supprimée): Donc généralement, on utilise des pointeurs pour tout ce que les références ne peuvent pas faire: Paramètres/variables membres optionnel(le)s, changement d'adresse pointée, indexation (tableaux nus), instanciation dynamique...

    PS: On n'utilise pas l'instanciation dynamique pour faire joli, ce n'est pas Java ici. On utilise l'instanciation dynamique quand on en a besoin.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Membre Expert Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 048
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 048
    Par défaut
    Bonjour Medinoc et merci pour ton intervention,

    Tout ce que tu dis je ne l'ai jamais remis en question ici. J'ai fais ça car je vois beaucoup trop souvent des pointeurs là où ce n'est pas nécessaire.
    Tu observeras que dans certains tests, je dis qu'il n'y a aucune différence. Notamment le passage en paramètre.

    Donc généralement, on utilise des pointeurs pour tout ce que les références ne peuvent pas faire: Paramètres/variables membres optionnel(le)s, changement d'adresse pointée, indexation (tableaux nus), instanciation dynamique...
    Bien sur, je l'ai dis dans le test.
    Hormis le faite que le pointeur peut ne pas être initialisé, par ça j'entends pointer sur l'adresse 0x00000000, et peut contrairement à la référence, référencer une nouvelle zone mémoire
    Tout ceci est surtout pour les nouveaux du C++, qui découvre le pointeur et l'utilise à toutes les sauces. Je n'ai jamais dis nul part que la référence pouvais toujours remplacer le pointeur.

  4. #4
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Hormis le faite que le pointeur peut ne pas être initialisé, par ça j'entends pointer sur l'adresse 0x00000000,
    Attention, ça c'est faux. Un pointeur non-initialisé n'est pas un pointeur nul.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Membre Expert Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 048
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 048
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Attention, ça c'est faux. Un pointeur non-initialisé n'est pas un pointeur nul.
    Oui je sais, le coup de l'adresse 0 étais plus pour dire que si il doit ne pas être initialisé il faudrait le mettre à 0 ne serait-ce que pour le tester. Une habitude que j'ai de toujours initialiser.
    Je vais améliorer ma diction

  6. #6
    screetch
    Invité(e)
    Par défaut
    j'avais posté sur un autre post, et je maintiens, que si une classe a une sémantique de valeur alors elle devrait etre passée par valeur (copie) ou bien par référence
    tandis que si une classe a une sémantique d'entité alors elle devrait être passée par pointeur

    la plupart des classes ont des sémantiques d'entité. C'est un concept similaire a la différence struct/class en C#: le code est généralement dans des entités, et travaille généralement sur/avec des valeurs. ca s'applique relativement bien en regle générale.

  7. #7
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Par défaut
    Citation Envoyé par Astraya Voir le message
    Tu observeras que dans certains tests, je dis qu'il n'y a aucune différence. Notamment le passage en paramètre.
    Ah ! Et pourtant, il y a une différence de taille dans le code ASM que tu montres. Cette différence est due au fait que tu passes une référence constante sur une entité qui a une taille suffisante pour tenir dans un registre. Du coup, et puisque la référence est constante, le compilateur a choisi de stocker la valeur contenue, et non pas une référence sur cette valeur. Il a optimisé sauvagement le code à ce niveau (avec raison).

    Si tu veux avoir un test plus pointu, il faudrait que tu crées un objet dont la taille est plus importante. Il faudrait aussi que le constructeur de cet objet exécute un certain nombre d'instruction, afin de ne pas être inliné par le compilateur (c'est ce qui fait que tu passe à très peu de code au moment de la création en mode release).

    A titre indicatif, on appelle pas cout - c'est un objet, pas une fonction C'est bien l'opérateur<<() qui est appelé (là, c'est une fonction). J'ai le sentiment que tu as quelques approximations dans ta lecture du code ASM, ce qui t'empêche de faire un lien tout à fait correct avec le code C++ correspondant.

    Ensuite, comparer références et pointeurs est d'un intérêt modéré. Les deux ont des comportements suffisamment différents pour qu'ils n'aient pas la même utilisation. Une référence existe dans le bloc où elle a été créée, et cesse d'exister dès qu'on sort de ce bloc. Ce n'est pas le cas pour un pointeur, dont la vie ne se termine que par appel explicite à l'opérateur delete (si la zone mémoire a été allouée grâce à new).

    Comparer la création dynamique de variable et la création statique est aussi assez injuste : il est évident que la création dynamique est plus lente, puisqu'il faut demander à l'OS de réserver une zone mémoire.

    En bref, si tu était vraiment cartésien, tu aurais vu que la seule chose que tu démontre c'est que l'utilisation d'un pointeur est, au niveau du code généré, strictement équivalente à l'utilisation d'une référence. La création d'un pointeur (enfin... c'est un abus de langage, vu qu'on ne crée pas de pointeurs. On les initialise, au mieux) dépends du mode de création choisi : s'agit-t-il d'un pointeur sur une variable existante (auquel cas cette cette initialisation est strictement équivalente à l'initialisation d'une référence) ou d'une allocation mémoire (auquel cas, bien évidemment, on ne peut guère comparer, puisqu'on ne peut pas allouer de référence).

    Tout ça pour dire que le corps de ton post contredit sa propre introduction, qui dit que l'accès par pointeur est plus lent que l'accès par une référence.

    Note supplémentaire : des instanciations sur la pile en mode release.
    Bien souvent, si le constructeur est court, cette instanciation est complètement optimisée : les paramètres sont stockés sur la pile de manière à directement former l'objet, et il n'y a pas besoin d'appeler le constructeur.

    Par exemple, une classe vecteur3d, dont le constructeur prends 3 floats (x, y, z). Pour des histoires d'alignement, le compilateur aligne la structure sur 16 bytes. Il n'y a qu'une seule variable locale définie à ce point. Le compilateur va probablement générer un code ressemblant au code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
      // la classe possède les variables v.x, v.y, v.z (dans cet ordre). 
      // en mémoire, on veut que cet ordre soit respecté, et qu'un padding
      // de 4 bytes (1 mot) soit ajouté à la fin de la structure. C'est une pile, 
      // donc on y empile les valeurs dans l'ordre inverse. 
      push z
      push y
      push x
      // ebp est le pointeur de pile. L'incrémenter va tout simplement
      // augmenter la taille de la pile. 
      incr ebp
      // récupération du pointeur vers l'instance de vector3d
      mov ecx, [ebp - 4]
    A ce moment, pointé par ecx, on a (x, y, z, padding), ce qui correspond à notre instance de vector3d. Et voilà, l'instance est créée, et ecx est prêt (visual C++ utilise ecx pour stocker this). Après cette initialisation, on est prêt à appeler une méthode de vector3d.

    Ce n'est qu'un exemple. Dans certains cas, l'appel du constructeur se fait longtemps après avoir réservé l'espace sur la pile. Si le constructeur n'est pas inliné, tu auras peut-être la possibilité de voir l'appel dans le code (appel explicite). Sinon, il te faut détecter l'endroit ou l'opération décrite dans le constructeur est appliquée.
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  8. #8
    Membre Expert Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 048
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 048
    Par défaut
    Et bien! Merci pour tout ça

    Je ne voulais pas mettre en avant le fait que la référence est TOUJOURS la solutions face aux pointeurs. Mais dans un contexte ou les deux peuvent si prêter, on retrouve souvent des pointeurs ou des références suffisent.

    A titre indicatif, on appelle pas cout - c'est un objet, pas une fonction C'est bien l'opérateur<<() qui est appelé (là, c'est une fonction)
    Euh oui là je sais pas ce qui m'a pris d'écrire "appel" .

    Ensuite, comparer références et pointeurs est d'un intérêt modéré. Les deux ont des comportements suffisamment différents pour qu'ils n'aient pas la même utilisation.
    Je conçois qu'elle n'ont pas la même utilisation, mais dans bien des cas, dans du code d'apprentissage. On va souvent voir des pointeurs là ou la référence peux suffire. Même si ce que tu dis au niveau des performances d'accès est vrai; au yeux d'une lecture objective du code,la référence reste plus lisible et intuitive d'utilisations. De plus, je reste persuadé que l'optimisation que le compilateur à faite est présente dans bien d'autres cas ou des pointeurs ont été utilisé, empêchant ainsi cette dite optimisation.

    Comparer la création dynamique de variable et la création statique est aussi assez injuste : il est évident que la création dynamique est plus lente, puisqu'il faut demander à l'OS de réserver une zone mémoire.
    Bas euh ....
    La création est sans aucun doute plus rapide de façon statique, mais le but du test n'est pas ici, je le présente quand même pour ceux qui voudrait comprendre la réel différence.
    Tout ça pour dire que le corps de ton post contredit sa propre introduction, qui dit que l'accès par pointeur est plus lent que l'accès par une référence.
    Voudrais tu dires que toutes les optimisations réalisables avec références sont réalisables avec pointeurs par le compilateur?

  9. #9
    Membre très actif
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    688
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 688
    Par défaut
    Salut,
    topic intéréssant.

    Question auxiliaire :

    MonInt* monIntPtr = new MonInt(33);

    ---------------------------------------------

    01261126 push 4
    01261128 call operator new (126152Ah)
    0126112D add esp,4
    01261130 mov dword ptr [ebp-2Ch],eax

    pourquoi faut-on ebp-2CH ici ? ebp c'est le registre de la Pile je crois

    Merci

Discussions similaires

  1. Equivalent pointeur - référence
    Par MAX-k dans le forum C#
    Réponses: 2
    Dernier message: 24/02/2010, 13h27
  2. Réponses: 6
    Dernier message: 06/03/2009, 06h44
  3. Différence entre référence et pointeur ?
    Par Vivian Pennel dans le forum Langage
    Réponses: 3
    Dernier message: 03/08/2007, 17h19
  4. [pointeurs/référence]
    Par poukill dans le forum C++
    Réponses: 18
    Dernier message: 10/05/2006, 11h49
  5. Réponses: 8
    Dernier message: 26/08/2004, 18h59

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo