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 en retour de fonction


Sujet :

C++

  1. #1
    Membre à l'essai
    Étudiant
    Inscrit en
    Juin 2008
    Messages
    32
    Détails du profil
    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2008
    Messages : 32
    Points : 21
    Points
    21
    Par défaut Référence en retour de fonction
    Bonjour

    J'essaie de prendre de plus en plus l'habitude d'utiliser des références au lieu de pointeur dans mes codes C++. Ce n'est pas facile car jusqu'à maintenant, j'ai beaucoup utilisé de pointeurs et changer les habitudes n'est pas évident.

    J'ai lu l'article "Pointeurs vs Références" dans la FAQ mais je n'arrive pas vraiment à comprendre dans la pratique où on utilise des références et où on utilise des pointeurs.

    Je me posais par exemple la question suivante. Si dans une fonction on crée un objet, on est obligé de le faire dynamiquement (avec new) si l'on souhaite que la durée de vie de l'objet continue après l'exécution de la fonction.

    J'imaginais donc la syntaxe suivante pour cette fonction si l'on souhaite créer (par exemple) une matrice dans la fonction et avoir en retour une référence vers cette matrice (au lieu d'un pointeur) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    Matrix & function()
    {
        Matrix * mat = new Matrix(3,5);
        return (*mat);
    }
    Je voulais donc savoir si ce genre de truc était vraiment utilisé ou pas ? Je voulais aussi savoir si c'était fréquent d'avoir des référence en retour de fonction ?

    Si vous avez quelques conseils concernant l'utlisation de références à la place de pointeurs, n'hesitez pas.

    Merci d'avance de vos réponse.

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 379
    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 379
    Points : 41 573
    Points
    41 573
    Par défaut
    Ah, non, on ne fait jamais ça!
    D'ailleurs, ma première réaction face à un tel code ressemblerait à cela :

    Tout new implique un delete. On ne fait pas de delete sur une référence...

    Par contre, on peut retourner un pointeur intelligent, qui lui serait un objet. Personnellement, j'ai tendance à préférer le comptage de références intrusif, mais il cause parfois des problèmes de const-correctness...

  3. #3
    Membre à l'essai
    Étudiant
    Inscrit en
    Juin 2008
    Messages
    32
    Détails du profil
    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2008
    Messages : 32
    Points : 21
    Points
    21
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Ah, non, on ne fait jamais ça!
    D'ailleurs, ma première réaction face à un tel code ressemblerait à cela :

    Tout new implique un delete. On ne fait pas de delete sur une référence...
    Ah effectivement je n'avais pas pensé à cela. Merci beaucoup pour ta réponse.

  4. #4
    Membre éclairé

    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    717
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 717
    Points : 858
    Points
    858
    Par défaut
    Mais en fait on fera plutôt ça
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Matrix function()
    {
        return Matrix(3,5);
    }

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 627
    Points : 30 692
    Points
    30 692
    Par défaut
    Salut,

    De prime abord, on décidera d'utiliser les référence chaque fois qu'un pointeur n'est pas indispensable.

    En gros, les pointeurs ne sont indispensables que dans deux cas particuliers:
    • quand tu as des références "cycliques":quand le contenu doit avoir une référence sur le contenant (ou cas similaires) ou quand un objet de type A qui contient un objet de type B, qui contient un objet de type C, qui contient un objet... de type A (ou, au plus simple: un objet de type A qui contient un objet de type... A)
    • Quand tu veux disposer du polymorphisme: tu dispose deux classes filles qui dérivent d'une même classe mère, et tu veux pouvoir faire cohabiter des instances des trois types dans un même conteneur (en les faisant passer pour des instance de la classe mère)

    D'un autre côté, on ne renverra une référence que si l'on a l'absolue certitude que la variable renvoyée continuera à exister en dehors de la méthode qui la renvoie.

    Ainsi, il est tout à fait possible de prévoir un code proche de
    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
    class A
    {
        public:
            A(const B& b):b(b){}
            A():b(){}
            ~A(){}
            /* const */ std::string& foo()
            {
                return b.theString();// OK: B::c existe tant que b existe, et
                                     // lui même continuera à exister tant que
                                     // l'instance de A existera
            }
            /* const */ B& getB()
            {
                return b; //ok... b continue à exister tant que l'instance de A
                          // existe
            }
            /*const*/ std::string& autreString(const std::string& p)
            {
                std::string str="salut "+p;
                return str; // NOK: str est détruite en sortie de fonction
            }
            /* par contre, ceci irait (mais couterait une copie de la chaine...
             * et c'est logique: on n'utilise pas de référence
             */
            /* const */ std::string foo(const std::string& p)
            {
                std::string str="salut "+p;
                return str;
            }
        private:
            B b;
    };
    class B
    {
        public:
            B(const std::string& c=""):c(c){}
            ~B(){}
            /*const */ std::string& theString(){return c;}
        private:
            std::string c;
    };

  6. #6
    Membre expérimenté

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Points : 1 543
    Points
    1 543
    Par défaut
    Salut,

    Citation Envoyé par Médinoc Voir le message
    Ah, non, on ne fait jamais ça!
    D'ailleurs, ma première réaction face à un tel code ressemblerait à cela :

    Tout new implique un delete. On ne fait pas de delete sur une référence...
    Je pense que le code suivant est valide :
    Ça va à l'encontre des conventions généralement observées, c'est sûr, mais à part ça je ne vois a priori rien qui l'interdise.

    MAT.

  7. #7
    Membre expérimenté

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Points : 1 543
    Points
    1 543
    Par défaut
    Citation Envoyé par koala01 Voir le message
    D'un autre côté, on ne renverra une référence que si l'on a l'absolue certitude que la variable renvoyée continuera à exister en dehors de la méthode qui la renvoie.
    En même temps pour un pointeur aussi, hein...

    MAT.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 627
    Points : 30 692
    Points
    30 692
    Par défaut
    Citation Envoyé par Mat007 Voir le message
    En même temps pour un pointeur aussi, hein...

    MAT.
    Oui, bien sur, mais d'un autre coté, si le pointeur pointe vers une instance (non membre) allouée dynamiquement, il y a moins de risque que la destruction de l'instance à partir de laquelle a été invoquée la méthode qui a effectué l'allocation dynamique provoque la libération de la mémoire et donc la destruction de l'instance pointée par le pointeur

    [EDIT]c'est pas clair du tout, ca... je reviendrai quand j'aurai trouvé le moyen de l'exprimer plus aisément

  9. #9
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    En gros, les pointeurs ne sont indispensables que dans deux cas particuliers:

    * quand tu as des références "cycliques":quand le contenu doit avoir une référence sur le contenant (ou cas similaires) ou quand un objet de type A qui contient un objet de type B, qui contient un objet de type C, qui contient un objet... de type A (ou, au plus simple: un objet de type A qui contient un objet de type... A)
    * Quand tu veux disposer du polymorphisme: tu dispose deux classes filles qui dérivent d'une même classe mère, et tu veux pouvoir faire cohabiter des instances des trois types dans un même conteneur (en les faisant passer pour des instance de la classe mère)
    Aucun de ces deux cas ne nécessite de pointeurs. En fait, rien ne nécessite d'utiliser des pointeurs où que ce soit.
    Bien entendu, je parle de l'interface des "briques". Pour faire certaines briques (structures de données, pimpl idiom, dynamic dispatch) il faut bien entendu des pointeurs, mais il peut s'agir uniquement de détails d'implémentation.

  10. #10
    Membre à l'essai
    Étudiant
    Inscrit en
    Juin 2008
    Messages
    32
    Détails du profil
    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2008
    Messages : 32
    Points : 21
    Points
    21
    Par défaut
    Citation Envoyé par Sylvain Togni Voir le message
    Mais en fait on fera plutôt ça
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Matrix function()
    {
        return Matrix(3,5);
    }
    Je n'arrives pas vraiment à comprendre à quoi correspond cette syntaxe.

    Est-ce que cela revient au même que :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    Matrix function()
    {
        Matrix mat(3,5);
        ....
        return mat;
    }

  11. #11
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 379
    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 379
    Points : 41 573
    Points
    41 573
    Par défaut
    Oui, mais cela engendre une copie, puisque que l'objet est retourné par valeur (même s'il y a les optimisations RVO et NRVO).

    De plus, il n'est plus question ici de polymorphisme, qui n'est possible que via référence ou pointeur...

  12. #12
    Membre à l'essai
    Étudiant
    Inscrit en
    Juin 2008
    Messages
    32
    Détails du profil
    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2008
    Messages : 32
    Points : 21
    Points
    21
    Par défaut
    Si par exemple je fais ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    template <typename T>
    inline Matrix<T> operator + (Matrix<T> & matrix1, Matrix<T> & matrix2)
    {
        Matrix<T> sumMatrix(matrix1.getNbRow(), matrix1.getNbColumn());
        ...
        return sumMatrix;
    }
    est-ce que ceci parait juste ?

    car lorsque j'essaie d'afficher ma matrice résultat de la façon suivante (je ne sais pas du tout si c'est juste de manipuler le retour de ma fonction opérateur de cette façon) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    (matrix1+matrix2).display();
    le programme plante.

  13. #13
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    C'est probablement parce que tu as mal redéfini ton constructeur de copie.

Discussions similaires

  1. Passage par référence et retour de fonction
    Par mister3957 dans le forum Langage
    Réponses: 2
    Dernier message: 16/05/2015, 13h12
  2. Retour de fonction par référence?
    Par ternel dans le forum Langage
    Réponses: 27
    Dernier message: 10/05/2014, 18h17
  3. référence sur retour de fonction
    Par Yoxoman dans le forum Langage
    Réponses: 1
    Dernier message: 25/05/2010, 17h39
  4. Référence en retour de fonction
    Par Dani3L dans le forum C++
    Réponses: 12
    Dernier message: 18/07/2008, 04h07
  5. Référence en retour de fonction, à transformer en hash
    Par raoulchatigre dans le forum Langage
    Réponses: 4
    Dernier message: 15/07/2005, 14h24

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