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 :

Passage par valeur & passage par référence


Sujet :

C++

  1. #1
    Membre à l'essai
    Inscrit en
    Février 2008
    Messages
    23
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 23
    Points : 20
    Points
    20
    Par défaut Passage par valeur & passage par référence
    Salut à tous,

    j'aimerais bien savoir dans quel cas on est obligé d'utiliser le passage par référence et dans quel cas on utilise le passage par valeur ?

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 631
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 631
    Points : 10 558
    Points
    10 558
    Par défaut
    Je vois 2 réponses
    • Passage par valeur pour des "Plain Old Data" (POD), par référence pour les classes
    • Passage par valeur pour les paramètres d'entrée (pas de modification) et par référence pour les paramètres de sortie (*) (modification, récupération de valeur)


    * -> Comme l'a dit leternel, on peut préciser const pour ne pas modifier une référence.

  3. #3
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    La référence ne copie pas l'objet.

    Si tu as un objet de 8Mo, tu préfères ne pas le copier pour le passer à une fonction.
    La solution, c'est le passage par référence (constante : T const&) (ou en C, par pointeur constant)

    L'autre avantage de la référence, c'est que si elle n'est pas constante (T &), tu peux modifier l'objet utilisé pour l'appel de la fonction.

    C'est comme cela que fonctionne cin >> variable.
    Il s'agit de l'appel de la fonction operator>>(istream&, T&) avec pour argument cin et variable.


    Il y a en fait trois modes de passages de paramètres:
    1. par valeur
    2. par référence constante
    3. par référence modifiante

    A cela s'ajoute le problème du pointeur, mais en C++, tu ne l'utiliseras pas sans une bonne raison.
    Un pointeur est plus ou moins comme une référence. (T const& correspondrait à T const&, et T * à T &).

    Le plus efficace est le passage par référence constante, dès que la variable est plus grosse qu'une référence (c'est à dire pour quasiment tout objet)
    Ca devrait être ton choix par défaut pour les classes.

    Les autres modes répondent à d'autres critères.

    Le passage par valeur est satisfaisant quand la variable est petite (un type primitif, ou une std::pair<int, int>, par exemple).
    Il est aussi intéressant quand on veut explicitement faire une copie de l'argument.
    par exemple, une fonction pourrait prendre un iterateur par copie, pour modifier cette copie en interne, sans modifier l'argument.

    par exemple std::distance pourrait être implémenté ainsi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    "unsigned int" distance( InputIt first, InputIt const& last) {
        unsigned int d = 0;
        while ((first++)!=last) d++;
        return d;
    }
    Comme les compilateurs peuvent faire ce qu'ils veulent tant que "tout se passe comme si" ils avaient fait comme tu demandes, tu peux même toujours passer une référence constante plutot qu'une copie.

    int f(int i) {return i;} et int f(int const& i) {return i;} devrait être compilées de la même manière.
    Je préfère cependant la première car elle est plus légère à lire.

    La référence modifiante correspond en général à une valeur de retour ou un contexte à modifier.
    si je reprends les operateurs >> de cin, tu as la forme complete suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    std::istream& operator>>(std istream& stream, Type & variable) {
        //...modifier variable avec cin
        return stream;
    }
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  4. #4
    Membre actif

    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2014
    Messages
    103
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2014
    Messages : 103
    Points : 224
    Points
    224
    Par défaut
    Salut,

    Lorsqu'un objet est passé par référence à une fonction, elle travaille directement sur l'objet qui a lui a été fourni : tous les traitements que la fonction fait subir à l'objet seront effectifs même après la fin de ta fonction.

    Lorsqu'un objet est passé par valeur à une fonction, l'objet est copié au préalable et c'est sur cette copie que ta fonction va travailler. En conséquence, l'objet que tu passes à ta fonction ne sera pas modifié par tes traitements.

    En gros, si on résume dans quels cas tu dois utiliser l'une ou l'autre des techniques :

    Passage par référence :
    • Tu veux éviter de recopier l'objet passé en argument (ce qui peut altérer les performances du programme en fonction de la taille de l'objet)
    • Tu veux que l'objet passé en argument soit modifié directement par les traitements de ta fonction


    Passage par copie :
    • Tu ne veux pas que l'objet passé en argument soit modifié


    J'espère avoir été clair et ne pas avoir dit de bêtise !

  5. #5
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Citation Envoyé par Jimmy91 Voir le message
    Passage par copie :
    • Tu ne veux pas que l'objet passé en argument soit modifié
    Ca c'est une bêtise, pour que l'objet ne soit pas modifié, c'est const qu'on utilise.

    Aujourd'hui, le passage par valeur en C++ moderne ne se justifie dans presque aucun cas. Il est tolérable pour les types primitifs. Sinon, j'applique les règles suivantes :

    Passage par référence (l-value-reference):
    • non constante si l'appelé doit modifier ou stocker une référence vers l'objet
    • constante dans tous les autres cas

    Passage par r-value-reference quand la propriété de l'objet doit être confiée à l'appelé.

    Le fait que la fonction appelée copie l'objet passé en argument est toujours possible avec une référence constante si l'objet est copiable, et devrait rester un détail d'implémentation. Si tu dois retenir une chose, une seule : exit le passage par valeur sauf pour les types primitifs de petite taille.
    Find me on github

  6. #6
    Membre actif

    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2014
    Messages
    103
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2014
    Messages : 103
    Points : 224
    Points
    224
    Par défaut
    Citation Envoyé par jblecanard Voir le message
    Ca c'est une bêtise, pour que l'objet ne soit pas modifié, c'est const qu'on utilise.
    Merci pour cette correction ! Au temps pour moi, je n'avais pas pensé au passage par référence constante.

  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 519
    Points
    41 519
    Par défaut
    Le passage par valeur est aussi utile dans une implémentation de l'idiome copy-and-swap (où une copie est de toute façon nécessaire), car il permet d'éviter une copie inutile dans certains cas.
    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
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Le passage par valeur sur autre chose qu'un type natif ou pointeur, tu devrais en avoir très peu, voire aucun.
    Le seul moment où tu passeras par valeur c'est justement parce que ta fonction a besoin de modifier une copie du paramètre. Et même dans ce cas, il sera souvent plus clair pour tous de déclarer le paramètre const& et faire une copie effectivement à l'intérieur.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  9. #9
    Membre à l'essai
    Inscrit en
    Février 2008
    Messages
    23
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 23
    Points : 20
    Points
    20
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Le passage par valeur sur autre chose qu'un type natif ou pointeur, tu devrais en avoir très peu, voire aucun.
    Le seul moment où tu passeras par valeur c'est justement parce que ta fonction a besoin de modifier une copie du paramètre. Et même dans ce cas, il sera souvent plus clair pour tous de déclarer le paramètre const& et faire une copie effectivement à l'intérieur.
    Si par exemple on a :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void incr(int &a)  //ça marchera jamais si la variable a n'est pas passée en référence lors de l'appel 
    {
        a++;
    }
    hors que dans ce qui suit (la fonction pgcd)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    int pgcd(int a, int b)   //aucun paramètre n'est passé en référence et ça marche lors de l'appel de la fonction en main() 
     {  int r;
       while (b != 0)
         {
              r = a%b ;
             a = b;
             b = r;
         }
         return a ;
    }

  10. #10
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Et donc, en quoi les propos de bousk contredisent-t-ils tes examples maiza_med ?
    Find me on github

  11. #11
    Membre à l'essai
    Inscrit en
    Février 2008
    Messages
    23
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 23
    Points : 20
    Points
    20
    Par défaut
    Citation Envoyé par jblecanard Voir le message
    Et donc, en quoi les propos de bousk contredisent-t-ils tes examples maiza_med ?
    J'voulais juste savoir pourquoi ça a marché pour la fonction PGCD(sans utiliser le &) pourtant notre fonction à modifier les paramètres ???

  12. #12
    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 519
    Points
    41 519
    Par défaut
    Non, elle modifie une copie des paramètres. Dans l'appelant, les valeurs passées pour a et b n'ont pas changé.
    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.

  13. #13
    Membre à l'essai
    Inscrit en
    Février 2008
    Messages
    23
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 23
    Points : 20
    Points
    20
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Non, elle modifie une copie des paramètres. Dans l'appelant, les valeurs passées pour a et b n'ont pas changé.
    En faite j'ai comparé les changements des paramètres de la fonction pgcd avec la fonction permut où le contenu sera changé :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void permut(int &x, int &y)
                { int z;
                z=y;
                y=x;
                x=z;
                }

  14. #14
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par maiza_med Voir le message
    Et j'ai constaté aussi que le passage par référence est utilisé beaucoup plus pour les procédure (void) dont on a pas un résultat (return) ????
    Mis à part que tu confonds tout et que ça n'a aucun rapport, je ne vois pas où tu espères en venir avec tes "exemples" ou cette phrase.
    Passer les paramètres par références pour les modifier, c'est un peu la base... et je vois pas ce que le type de retour vient faire là-dedans ?
    Tu veux modifier un paramètre ? Tu utilises une référence ou un pointeur. Tu veux retourner une valeur ? Tu retournes une valeur... (captain obvious inside)
    Tu veux faire les 2 ? Fais les 2! Ce sont juste 2 choses complètement orthogonales. Exemple, au hasard, une fonction bool Find(T* p).
    En plus ce terme de procédure, ça fait un moment que je l'ai pas entendu, surtout en C++.

    Btw, la copie ou const& est également le seul moyen de passer des litéraux à une fonction. Là où une référence exigera d'utiliser une vraie variable.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 6
    Dernier message: 20/01/2013, 14h08
  2. Réponses: 6
    Dernier message: 18/05/2012, 12h07
  3. Réponses: 2
    Dernier message: 15/06/2011, 11h13
  4. Réponses: 12
    Dernier message: 26/01/2008, 20h23
  5. Passage par référence et non pas par valeur
    Par GPZ{^_^} dans le forum Flash
    Réponses: 2
    Dernier message: 14/05/2007, 15h21

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