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

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

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

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 043
    Points : 2 234
    Points
    2 234
    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.
    Homer J. Simpson


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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    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 chevronné Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 043
    Points : 2 234
    Points
    2 234
    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.
    Homer J. Simpson


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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    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 chevronné Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 043
    Points : 2 234
    Points
    2 234
    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
    Homer J. Simpson


  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
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    C'est une bonne théorie, mais attention à la pratique, quand il est question de données volumineuses (copy-on-write, etc.)
    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.

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

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

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 043
    Points : 2 234
    Points
    2 234
    Par défaut
    Pour ma part, un passage par copie ne devrait être que les types de bases, et dans certains cas bien précis, des copies de classes. Le pointeur dans tout les cas où la référence ne peut pas ce prêter comme la dit le premier poste de Médinoc.
    Homer J. Simpson


  9. #9
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    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
    Points : 4 551
    Points
    4 551
    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.

  10. #10
    Membre chevronné Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 043
    Points : 2 234
    Points
    2 234
    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?
    Homer J. Simpson


  11. #11
    Débutant
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    688
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 688
    Points : 176
    Points
    176
    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

  12. #12
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Salut,
    Citation Envoyé par guillaume07 Voir le message
    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
    Il semblerait que les registres de pile sont SS (Stack Segment) et SP(Stack Pointeur), voire ESP (extended Stack Pointer).

    D'après le wiki, EBP n'est, en définitive, qu'un registre étendu plus ou moins quelconque
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    EBP: Frame Pointer.
    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.

  14. #14
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Citation Envoyé par screetch Voir le message
    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
    Je ne vois pas en quoi l'utilisation d'une référence ne devrait pas être utilisée pour une classe à sémantique d'entité.
    Une référence ne copie/crée pas un objet mais crée un alias sur un objet, au final c'est, dans l'esprit, un comportement assez proche de l'utilisation d'un pointeur modulo la non nullité, la constance, etc.

  15. #15
    Membre habitué
    Homme Profil pro
    En rupture avec la societé
    Inscrit en
    Novembre 2008
    Messages
    144
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : En rupture avec la societé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 144
    Points : 194
    Points
    194
    Par défaut
    bonsoir,

    un point de vue débutant, c'est a dire moi même.
    Je tenais a souligner que sur mon cycle de formation on nous stipule bien que le passage par valeur implique obligatoirement la copie de l'objet.

    Ce qui n'est pas le cas du passage par référence. puisque celui ci passe un simple alias de l'adresse mémoire.

    De façon général : la différence entre un pointeur (une variable qui contient une adresse mémoire) et une référence (l'alias de cette même variable...).

    Ce même cycle, nous invoque bien la différence entre une déclaration sur la pile, avec les conséquence de gestion (FIFO), et une instanciation sur le tas et la différence de l'accès de l'objet via cette allocation dynamique (héritage et polymorphisme), le mode d'accès a l'adresse allouée et les conséquences de la non destruction.

    avec la lecture de ce genre de topic (les avis divergeant quand a la manipulation, en m'expriment de façon simple) j'en arrive a me posé bien des questions sur l'utilisation des pointeurs.

    Je lis de façon journalière divers topics sur le forum, et sans vouloir agresser Astraya, je trouve que tu as une méfiance accru avec l'utilisation des pointeur (il y a certainement du vecu) et que tu ne tiens pas toujours compte que pour un développeur débutant le pointeur est une solution idéal(attention je généralise).

    Je trouve cela dommage car je pense qu'il n'est pas de mise suivant le contexte et la façon dont le topic est exprimé. D'un point de vue technique je pense que tu as certainement raison quand a savoir la façon de faire.

    d'un point de vue pédagogique, le développeur ce retrouve dans une situation ou il se pose vraiment la question: mais alors pourquoi les pointeurs et surtout pourquoi de tel danger dans leurs utilisations.

    Pour ma part les dangers sont déjà vécu avec mes propre tests de dev. Et cela ne me fera pas changé d'avis sur l'utilité des pointeurs.
    Souvent, lorsque tu es dans l'obligation de mixer c et c++, l'utilisation du pointeur s'impose et bien souvent la ou ce n'est pas utile.

    amicalement.

  16. #16
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par burndev Voir le message
    bonsoir,

    un point de vue débutant, c'est a dire moi même.
    Je tenais a souligner que sur mon cycle de formation on nous stipule bien que le passage par valeur implique obligatoirement la copie de l'objet.

    Ce qui n'est pas le cas du passage par référence. puisque celui ci passe un simple alias de l'adresse mémoire.
    La question n'est pas forcément de savoir s'il y a copie ou non de la variable lorsqu'on la transmet par référence, car elle ne se pose, de toutes façons, pas, mais de savoir ce qui se passe réellement au niveau du processeur.

    Le test présenté ici indique que, dans le meilleur des cas, la variable sera placée directement dans un registre afin d'être directement utilisable

    La question est "que se passe-t-il si la variable est trop grande pour prendre place dans un registre", et la réponse à cette question (que l'on ne trouve pas dans le test ci-dessus) a de forte chance d'être "l'adresse de la variable est transmise, et placée dans un registre"
    De façon général : la différence entre un pointeur (une variable qui contient une adresse mémoire) et une référence (l'alias de cette même variable...).
    C'est, effectivement, sous cette forme que l'on présente les choses... Sauf qu'elle ne veut pas dire grand chose en soi :

    les grosses différences qu'il y a sont:
    1. un pointeur peut être null, pas une référence
    2. un pointeur peut référencer une variable différente, alors que la référence ne peut pas
    3. un pointeur permet difficilement d'assurer la constance, alors que la référence le permet de manière très simple
    4. la syntaxe d'utilisation d'un pointeur est différente de celle de l'objet pointé, alors que la syntaxe d'utlisation d'une référence est identique à celle de l'objet référencé
    C'est sur cette base que l'on conseille globalement d'utiliser la référence (éventuellement constante) "à chaque fois que possible" et de n'utiliser le pointeur que "lorsque l'on n'a pas le choix" (entre autre, lorsqu'il n'existe aucune autre manière d'autoriser la non existence de l'objet)
    Ce même cycle, nous invoque bien la différence entre une déclaration sur la pile, avec les conséquence de gestion (FIFO),
    Ce n'est qu'un détail, mais une pile présente une gestion en ... LIFO (Last In, First Out): tu ne peux pas retirer autre chose que le dernier objet ajouté sans risquer de te "ramasser" l'ensemble des éléments ajoutés après celui que tu essaye de retirer sur le coin de la figure
    avec la lecture de ce genre de topic (les avis divergeant quand a la manipulation, en m'expriment de façon simple) j'en arrive a me posé bien des questions sur l'utilisation des pointeurs.
    La réponse à toutes tes question te sera donnée en ne t'en posant qu'une seule: Ai-je la possibilité de faire autrement
    • Si tu ne dois pas autoriser la nullité de l'objet ou
    • Si tu ne dois pas "retarder" la création de l'objet ou
    • Si tu veux éviter la copie, mais que tu ne dois pas modifier l'objet "référencé"
    tu ne dois pas utiliser le pointeur
    Je lis de façon journalière divers topics sur le forum, et sans vouloir agresser Astraya, je trouve que tu as une méfiance accru avec l'utilisation des pointeur (il y a certainement du vecu)
    Astraya est très loin d'être le seul "détracteur" des pointeurs par rapport aux références

    S'il est vrai que le vécu modifie considérablement la manière d'aborder certaines choses, il n'en reste pas moins que les quatre différences que j'ai citées plus haut te permettent de constater que tu peux très facilement "sécuriser" ton code en utilisant les références chaque fois que possible

    La liste des inconvénients liés à l'utilisation des pointeurs est, en effet, assez impressionnante (et a été rappelée plusieurs fois ces derniers jours (dernières semaines) )
    et que tu ne tiens pas toujours compte que pour un développeur débutant le pointeur est une solution idéal(attention je généralise).
    C'est, de mon point de vue (et je sais qu'il est partagé par un grand nombre d'intervenants ) une fausse solution idéale.

    Elle parait idéale uniquement parce que grand nombre de gens qui essayent de faire apprendre C++ ont baigné pendant longtemps dans la culture C, par le fait que C++ descend "en droite ligne" de C, et que les pointeurs sont omniprésents en C.

    Le problème c'est, même si je me répète, que les pointeurs présentent énormément d'inconvénients qui sont "gommés" par les références.

    De plus, il est tout à fait possible d'apprendre le C++ en ne devant aborder la notion de pointeur que... lorsqu'il s'agit de gérer une collection d'objets polymorphes.

    C'est à dire, une fois que la syntaxe est parfaitement comprise et que l'on a même correctement compris les bases de la programmation OO que sont l'héritage et le polymorphisme
    Je trouve cela dommage car je pense qu'il n'est pas de mise suivant le contexte et la façon dont le topic est exprimé.
    Que trouve tu dommage que le topic montre qu'il est, décidément, plus efficace d'utiliser les références, ou que le pointeur paraissent être la solution idéale
    D'un point de vue technique je pense que tu as certainement raison quand a savoir la façon de faire.
    cf plus haut
    d'un point de vue pédagogique, le développeur ce retrouve dans une situation ou il se pose vraiment la question: mais alors pourquoi les pointeurs et surtout pourquoi de tel danger dans leurs utilisations.
    Une grosse part du danger de leur utilisation vient de ce qu'ils sont régulièrement associés à la gestion dynamique de la mémoire.

    Cela implique:
    • Que l'on aura souvent tendance à lancer un delete lorsque l'on n'a plus besoin de ce qui est pointé par le pointeur, mais:
    • delete sur un objet déclaré sur la pile fera planter le programme
    • Si on ne libère pas la mémoire allouée à l'objet pointé avant d'affecter une autre adresse au pointeur, on a une fuite mémoire, qui finira, à terme, par mettre la stabilité de l'ensemble du système à mal
    • à l'inverse, si on libère la mémoire trop tôt, on risque de vouloir accéder à quelque chose qui n'existe plus, et d'obtenir des résultats aberrants
    • Si on ne décide pas une bonne fois pour toutes qui libère la mémoire et quand, et, surtout, si on ne respecte pas cette décision, on risque d'observer des tentatives de double libération de la mémoire, qui feront immanquablement planter l'application
    • On n'a a priori aucun moyen de savoir si ce qui se trouve à l'adresse contenue du pointeur est un objet unique ou un ensemble d'objet contigus en mémoire, et, dans ce cas, combien d'objets contigus sont réservés. Une incrémentation de trop enverra le processeur "cueillir les marguerites", et provoquera des résultats aberrants qui peuvent n'apparaitre que bien plus tard (avec leur lot de difficultés à retrouver "ce qui a foutu le bordel", et donc un temps de débuggage particulièrement important)
    • Il est particulièrement difficile, lorsqu'un pointeur est partagé entre différents objets, de déterminer quand la mémoire sur laquelle il pointe peut réellement être libérée (du moins, lors de l'utilisation de pointeurs nus)
    • j'oublie surement certains inconvénients, mais rien que ceux que j'ai cités ici devraient t'inciter à réfléchir à deux fois avant d'utiliser les pointeurs

    Pour ma part les dangers sont déjà vécu avec mes propre tests de dev. Et cela ne me fera pas changé d'avis sur l'utilité des pointeurs.
    C'est sans doute parce que tu n'as pas encore pris l'occasion d'expérimenter sereinement la sécurité que peuvent apporter les références

    Tu devrais peut être t'intéresser à certains aspects connexes, qui te permettraient de changer d'avis, tels que:
    • la const-correctness ou le fait de déclarer constant tout ce qui ne doit pas être modifié
    • l'utilisation de variable anonymes temporaires (très utiles pour s'éviter des problèmes, hyper-faciles à mettre en oeuvre avec les références constantes, particulièrement difficile à envisager avec les pointeurs)
    • ...

    Souvent, lorsque tu es dans l'obligation de mixer c et c++, l'utilisation du pointeur s'impose et bien souvent la ou ce n'est pas utile.
    Elle ne s'impose à vrai dire que lorsque tu dois, effectivement, renvoyer quelque chose de C++ vers C.

    Mais le plus souvent, tu auras d'autres barrières à surmonter à ce moment là, comme, par exemple, la nécessité de travailler avec des types POD (Plain Old Data), et donc de t'assurer de la conversion de objets C++ en structures C
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  17. #17
    Membre chevronné Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 043
    Points : 2 234
    Points
    2 234
    Par défaut
    Je lis de façon journalière divers topics sur le forum, et sans vouloir agresser Astraya, je trouve que tu as une méfiance accru avec l'utilisation des pointeur (il y a certainement du vecu) et que tu ne tiens pas toujours compte que pour un développeur débutant le pointeur est une solution idéal(attention je généralise).
    Oh ne t'inquiète pas, on est là pour échanger des idées, pas pour pendre les gens . En faite, à mes début en C++, je ne pensais que copie et pointeur, et je ne comprenais vraiment pas l'intérêt d'une référence car le pointeur fesais déjà tout et je pensais à tord que c'était la solutions idéal pour ne pas ce casser le crâne et réussir mes cours . Par la suite, j'ai acquis des expériences, des avertissements avec des preuves niveau code de formateur et professionnel, parfois très complexes ou je passais 1 heures à comprendre rien que le code. Au final, on ce rend compte que la référence et le pointeur fond le même boulot globalement, mais la référence apporte de la sécurité supplémentaire au dépend des possibilités du pointeur à pouvoir faire ce que la référence ne fait pas, comme la dit Koala juste en haut.

    Dans mon test, j'ai réalisé quelques erreurs, mais une chose est clair, et Emmanuel Deloget à mit le doigt dessus. Le compilateur peut optimiser des références mais ne le feras pas pour des pointeurs. Dans un code ou l'on préféreras faire beaucoup de petite classe, plutôt que des très grosses classe, ce genre d'optimisation peut payer.

    Et pour compléter Koala, j'ajouterais que le polymorphisme est également possible via des références! Je ne connais l'intérêt de le réaliser via références ou pointeurs sur le coup, mais c'est toujours bon de savoir que ça fonctionne également.

    Un pointeur devrais être utilisé " Quand on ne peut pas faire autrement. "
    Homer J. Simpson


  18. #18
    Membre chevronné
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    Citation Envoyé par burndev Voir le message
    bonsoir,

    un point de vue débutant, c'est a dire moi même.
    Je tenais a souligner que sur mon cycle de formation on nous stipule bien que le passage par valeur implique obligatoirement la copie de l'objet.
    ce qui est faux... mais bon passons. (c'est normal qu'on vous dise ça).


    Je lis de façon journalière divers topics sur le forum, et sans vouloir agresser Astraya, je trouve que tu as une méfiance accru avec l'utilisation des pointeur (il y a certainement du vecu) et que tu ne tiens pas toujours compte que pour un développeur débutant le pointeur est une solution idéal(attention je généralise).
    Au contraire, ça peut paraitre idéal, mais ça ne l'est pas du tout. Au contraire, c'est dangereux, excessivement dangereux.
    (je parle de pointeur nus ici hein).
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  19. #19
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par Astraya Voir le message
    Et pour compléter Koala, j'ajouterais que le polymorphisme est également possible via des références! Je ne connais l'intérêt de le réaliser via références ou pointeurs sur le coup, mais c'est toujours bon de savoir que ça fonctionne également.
    Ben, je l'avais dit, de manière, détournée ici:
    De plus, il est tout à fait possible d'apprendre le C++ en ne devant aborder la notion de pointeur que... lorsqu'il s'agit de gérer une collection d'objets polymorphes.

    C'est à dire, une fois que la syntaxe est parfaitement comprise et que l'on a même correctement compris les bases de la programmation OO que sont l'héritage et le polymorphisme
    Il est tout à fait possible d'envisager le polymorphisme sans l'allocation dynamique de la mémoire (et donc en recourant aux références plutôt qu'aux pointeurs) tant que tu ne dois pas gérer une collection d'objets polymorphes.

    Cela implique, bien sur que tu n'aies besoin que d'un nombre fini d'objets dont le type soit clairement défini à dés le départ, mais cela apporte la certitude, étant donné le mode de fonctionnement de la pile, que tout objet créé en utilisant une référence sur un objet polymorphe aura été détruit avant que l'on en arrive à essayer de détruire ce dernier:
    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
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    class Base
    {
        public:
            virtual void talk() const{std::cout<<" Je suis une base"<<std::endl;}
            /* le destructeur n'a même pas besoin d'être virtuel dans le cas
             * présent, car nous n'essayerons jamais de détruire les instances 
             * des classes dérivées en les faisant passer pour des Base
             */
    };
    class Derivee1 : public Base
    {
        public:
            virtual void talk() const{std::cout<<"je suis une Derivee"<<std::endl;}
    };
    class AutreDerivee : public Base
    {
        public:
            virtual void talk() const{std::cout<<"je suis une AutreDerivee"
                                               <<std::endl;}
    };
    class User
    {
        public:
            User(Base /* const */ & b):b_(b){}
            void callTalk() const{b_.talk();}
        private:
            Base /* const */ & b_;
    };
    int main()
    {
        Base b;
        Derivee d;
        {
            AutreDerivee ad;
            User uad(ad);
            uad.callTalk();
     
            User ud(d);
            ud.callTalk();
        } /* destruction, dans l'ordre, de 
           * 1- ud,
           * 2- uad,
           * 3- ad
           */
        User ub(b);
        User ud2(d);
        ub.callTalk();
        ud2.callTalk();
        return 0;
    } /* destruction dans l'ordre de
       * 1- ud2
       * 2- ub
       * 3- d
       * 4- b
       */
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  20. #20
    Membre chevronné Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 043
    Points : 2 234
    Points
    2 234
    Par défaut
    Ben, je l'avais dit, de manière, détournée ici:
    Autant pour moi
    Homer J. Simpson


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