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 :

Référence invalide, comment ça marche ?


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre chevronné Avatar de Rafy
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    415
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 415
    Par défaut Référence invalide, comment ça marche ?
    Une référence, ne peut pas être invalide, contrairement aux pointeurs.
    Ca c'est ce qu'on dit toujours à propos des références, c'est peut-être même dans la définition.
    Elle est initialisée à la création et ainsi ne peut pas 'pointer' sur NULL comme un pointeur pourrait le faire.

    Mais quand une référence 'pointe' sur un objet qui est détruit :
    Nous avons deux cas possibles :
    La référence était précédement valide.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include <iostream>
    int i = 2;
    int& refi = i;    // refi est initialisée avec i
    {
            int j = 7;    // Ici la porté de j est limité jusqu'a la fin des accolades...
            refi = j;
            std::cout << "Entre les accolades : refi = " << refi << std::endl;    // Affiche 7
    }
    // Ici refi est 'invalidée' car j n'existe plus
    std::cout << "Juste après les accolades : refi = " << refi << std::endl;    // Affiche 2
    // Mais comme les références c'est pas trop bête,
    // en fait ça reprend la dernière référence valide, soit la référence sur i
    La tout se passe bien car la référence à déjà eu une valeur valide, celle de i avant d'avoir une valeur 'invalide'.

    La référence est initialisé avec un élément qui va devenir invalide.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include <iostream>
    class A
    {
        public:
            int i;
    };
    A* pA = new A;
    pA->i = 2;
    int& refi = pA->i;
    std::cout << "Avant la destruction : refi = " << refi << std::endl;
    delete pA;
    std::cout << "Après destruction : refi = " << refi << std::endl;
    Dans ce cas la référence est valide à sa création, elle initialisée. Avant la destruction le premier cout nous dit que refi vaut 2, comme il faut.
    Et le second nous donne également 2. Mais la référence n'est plus valide car pA->i n'existe plus car pA à été détruit...
    Donc en fait refi 'pointe' sur un endroit de la mémoire qui était utilisé avant pour stocker la valeur de i, donc 'vaut' toujours 2, mais c'est comme un pointeur, qui pointait sur un objet que l'on vient de détruire....

    Ma question :
    Est il possible que quelqu'un me dise si je dis faut ou non.
    Si oui ou est ma faute?

    Si non n'est-il pas plus dangereux de se servir des réference dans le cadre des exemples ci-dessus ?
    Il est possible de trouver d'autre cas similaires ou les références sont 'invalides'.

    J'ai mis pointe, vaut et invalide car je ne sais pas si on peut parler des références avec le vocabulaire des pointeurs.

    (compilation et tests réalisés avec VisualStudio 2005, pas de problème de compilation ni de lieur, pas d'avertissement même niveau 4)

  2. #2
    Membre confirmé Avatar de b Oo
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 179
    Par défaut
    Salut,
    tu es sûr que ton premier exemple produit le résultat que tu as dis ?
    Je pense plutôt que les deux fois refi affiche 7.

    En effet, tu peux considérer refi comme i lui-même (moi je le considère comme un pointeur constant sur i, mais ce n'est pas l'avis de tout le monde : http://c.developpez.com/faq/cpp/?pag...TION_reference).
    Donc quand tu fais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    int j = 7;
    refi = 7; // equivalent à i = 7
    C'est i qui est modifié et non refi (qui pointe toujours sur i).

    Pour le deuxième exemple, je pense que ton explication est la bonne (si on considère que refi est un pointeur constant sur pA), à moins que lorsque l'on détruit pa cela détruise aussi la référence (à voir).

    b Oo

  3. #3
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Citation Envoyé par Rafy
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    #include <iostream>
    int i = 2;
    int& refi = i;    // refi est initialisée avec i
    {
            int j = 7;    // Ici la porté de j est limité jusqu'a la fin des accolades...
            refi = j;
    Ce code ne fait pas ce que tu crois... Il ne fait en rien de refi une référence à j. Il affectue juste à ce à quoi refi fait référence la valeur de j. Elle est équivalente à i=j;
    Citation Envoyé par Rafy
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include <iostream>
    class A
    {
        public:
            int i;
    };
    A* pA = new A;
    pA->i = 2;
    int& refi = pA->i;
    std::cout << "Avant la destruction : refi = " << refi << std::endl;
    delete pA;
    Là, problème : Tu fais une chose qui est interdite en C++. La suite de ton programme est en droit de faire n'importe quoi.

    Quand on dit qu'une référence est toujours valide, ça veut dire qu'il est impossible d'avoir une référence invalide, car toutes les temtatives pour faire conduisent à des comportement indéfinis auparavant.
    Et donc, il ne sert à rien (et il n'est pas possible) de vérifier la validité d'une référence, car :
    - Soit le programme est valide, et la référence le sera
    - Soit le programme n'est pas valide, et de toute façon, on ne peut rien dire sur son comportement.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  4. #4
    Membre chevronné Avatar de Rafy
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    415
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 415
    Par défaut
    Je crois voir ce que tu veut dire pour l'exemple 1;
    Pour ce qui est du second exemple je ne vois pas à quelle ligne j'ai fais un truc interdit...

  5. #5
    Membre Expert
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Par défaut
    Il affectue juste à ce à quoi refi fait référence la valeur de j. Elle est équivalente à i=j;
    En effet une référence, comme un pointeur, est une sorte "d'intermédiaire" vers un autre objet.

    Mais alors comment faire pour réafecter une référence, faire en sorte qu'elle se réfère à un autre objet?

  6. #6
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Citation Envoyé par seriousme
    Mais alors comment faire pour réafecter une référence, faire en sorte qu'elle se réfère à un autre objet?
    Ce n'est pas possible.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  7. #7
    Membre chevronné Avatar de Rafy
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    415
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 415
    Par défaut
    Ouais c'est bien ce que je me disais à propos du 'reréférencement'...
    C'est pas possible. Donc en fait les références et les pointeurs ont chaqun leurs avantages et leurs inconvénients.... Je trouve quand même que c'est beaucoup plus vicieux que les pointeurs...
    J'utilise la règle suivante pour les passages par arguments :
    -> Utilisation d'une référence constante pour passer un objet par argument à une méthode ou fonction si elle ne modifie pas l'objet.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    void Fonction1(const Objet& ObjetQuiNeSeraPasModifié)
    -> Utilisation d'un pointeur (intelligent ou non) pour un passage d'objet, par argument, qui sera ou sera suceptible d'être modifié.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    void Fonction2(Objet* ObjetQuiSeraPeutEtreModifie)
    Mais le but de mon post était d'éclaircir certains points sur les références....
    Donc les références c'est bien mais MEF!!!
    Merci à tous pour vos réponses.

  8. #8
    Membre Expert
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Par défaut
    Citation Envoyé par JolyLoic
    Ce n'est pas possible.
    Pas cool!

    Sinon comment se "débarrasser" d'une référence quand elle ne sert plus?
    Ca aussi c'est impossible?

  9. #9
    Expert confirmé

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 756
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 756
    Billets dans le blog
    3
    Par défaut
    Citation Envoyé par seriousme
    En effet une référence, comme un pointeur, est une sorte "d'intermédiaire" vers un autre objet.

    Mais alors comment faire pour réafecter une référence, faire en sorte qu'elle se réfère à un autre objet?
    c'est ce qui distingue une référence d'un pointeur.

  10. #10
    Expert confirmé
    Avatar de Swoög
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    6 045
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 6 045
    Par défaut
    Citation Envoyé par Rafy
    Je crois voir ce que tu veut dire pour l'exemple 1;
    Pour ce qui est du second exemple je ne vois pas à quelle ligne j'ai fais un truc interdit...
    en fait, tu fais déjà un truc pas bien : l'encapsulation n'est pas respectée dans ta classe, il est très dangeureux de donner un accès par référence à un donnée membre d'une classe. On s'en accomode dans certains cas (opérateurs *, -> ou encore []) mais c'est jamais le top ! Il faut garder à l'esprit que c'est une faille dans la classe puisqu'on peut logiquement faire n'importe quoi avec cette variable)

    ensuite, ton code revient à dire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int* a = new int;
    int *b = a;
    delete a;
    *b = 5;
    et là ? il se passe quoi ?

    ça plante, normal, et bien c'est exactement ce que fait ton code...

    Le problème des pointeurs fantomes est impossible à éviter en C++ à moins d'utiliser une classe de smart pointeur qui ne donne aucun accès en référence à la variable, et c'est très dur à faire pour ne pas dire quasi-impossible !

    Toujours est-il comme l'a dit JoyLoic que les références sont, dans tous les cas plus sécurisée que les pointeurs, même si bien sûr elles ne sont pas parfaites...
    Rédacteur "éclectique" (XML, Cours PHP, Cours JavaScript, IRC, Web...)
    Les Règles du Forum - Mon Site Web sur DVP.com (Développement Web, PHP, (X)HTML/CSS, SQL, XML, IRC)
    je ne répondrai à aucune question technique via MP, MSN ou Skype : les Forums sont là pour ça !!! Merci de me demander avant de m'ajouter à vos contacts sinon je bloque !
    pensez à la balise [ code ] (bouton #) et au tag :resolu: (en bas)

Discussions similaires

  1. ToAsciiEx, comment cela marche ?
    Par mikyfpc dans le forum C++Builder
    Réponses: 2
    Dernier message: 17/02/2004, 21h39
  2. [MFC] list box : comment ça marche
    Par runn2 dans le forum MFC
    Réponses: 4
    Dernier message: 28/01/2004, 12h36
  3. [SYNEDIT] -> Comment ça marche ?
    Par MaTHieU_ dans le forum C++Builder
    Réponses: 2
    Dernier message: 18/01/2004, 19h11
  4. [TP][Turbo Vision] comment ça marche ??
    Par Costello dans le forum Turbo Pascal
    Réponses: 7
    Dernier message: 05/08/2003, 00h24
  5. [update][req. imbriquee] Comment ca marche ??
    Par terziann dans le forum Langage SQL
    Réponses: 3
    Dernier message: 11/07/2003, 12h51

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