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 référence versus par pointeur


Sujet :

C++

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Février 2008
    Messages
    29
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 29
    Par défaut Passage par référence versus par pointeur
    Bonjour,

    Je cherche à comprendre la différence entre un passage par référence versus un passage par pointeur. Pour moi, ça fait la même chose, à part que la syntaxe est différente. Dans les deux cas, les modifications sont faites directement sur la valeur origniale et il n'y a pas de copie temporaire. Est-ce que c'est préférable d'utiliser l'un à l'autre dans certaines situations ?

    Code Reference : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void test(Image &img){
    ...
    }


    Code Pointeur : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    void test(Image * img){
    ...
    }
    merci !

  2. #2
    Membre émérite Avatar de SofEvans
    Homme Profil pro
    Développeur C
    Inscrit en
    Mars 2009
    Messages
    1 082
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Développeur C

    Informations forums :
    Inscription : Mars 2009
    Messages : 1 082
    Par défaut
    Bonsoir.

    Je suis debutant en C++, donc je vais peut etre raconter des betise.

    Mais bon.

    Dans le fond, tu as raison : passage par reference ou passage par pointeur font la meme chose, ils changent le contenu de la variable pointé/referencé.
    Cependant, il est infiniment plus simple d'utiliser une reference qu'un pointeur.
    Les erreurs de memoire sont moins frequente (voir inexistante puisqu'une reference ne peut changer de referent).

  3. #3
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 633
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 633
    Par défaut
    Salut, et bienvenue sur le forum.

    Effectivement, si l'on compare le code exécutable généré lors de l'utilisation d'un pointeur et celui généré lors de l'utilisation d'une référence, on remarque... qu'il est strictement identique.

    Cependant la référence a l'énorme avantage sur le pointeur d'apporter une garantie de non nullité, et de respecter la constance.

    En effet, une référence doit être initialisée (pour représenter un objet existant) au moment de sa déclaration ou, s'il s'agit d'un membre de classe, au moment de la création de l'objet au grand plus tard (dans la liste d'initialisaton).

    Ainsi, alors que le code suivant serait accepté:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Type * ptr; // ptr pointe strictement n'importe où... sans doute
                // dans les "matitis"
    tu ne peux envisager de déclarer une référence qu'en... lui indiquant directement l'objet dont elle se fait l'alias:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    /* cette ligne est refusée à la compilation */
    Type & badRef;
    /* pour que ce soit accepté, il faut l'initialiser directement */
    type obj;
    Type & ref = obj;
    Cela ne veut pas dire qu'il est tout à fait impossible d'obtenir une référence invalide, mais le risque est limité au stricte minimum, et tout compilateur bien réglé sera en mesure d'au minimum émettre un avertissement à ce sujet

    Le cas typique dans lequel on obtiendra une référence invalide sera celui dans lequel on essaye de renvoyer par référence un objet "temporaire" (créé au sein d'une fonction) comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Type & foo()
    {
        Type t;
        /* ... */
        return t; // nous aurons au minimum l'avertissement "reference to
                  // locale variable 't' returned " (si le compilateur est bien réglé)
    };
    En ce qui concerne la constance, elle va s'appliquer, pour les pointeurs, différemment en fonction de l'endroit où se trouve le mot clé const:

    S'il se trouve soit à gauche du type (ce qui est une écriture régulièrement utilisée mais qui représente en fait une règle particulière) ou entre le type et l'étoile indiquant que l'on a un pointeur, il s'applique à l'objet pointé.

    Ainsi le code suivant sera refusé:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int i=3;
    const int * ptr =&i; // revient au même que int const * ptr = &i;
    ++*ptr; // ptr pointe sur un objet constant, on ne peut donc pas 
            // modifier l'objet
    et, s'il est à droite de l'étoile, il indique que le pointeur ne pourra pas pointer vers un autre objet (sans pour autant assurer la constance de l'objet pointé).

    Ainsi, si le code suivant sera accepté
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int i=4;
    int * const ptr=&i; //C'est le pointeur qui est constant, pas l'objet
    ++*ptr;
    cout<<*ptr; // affiche "5"
    mais le code suivant sera refusé (car le pointeur ne peut pas être modifié)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int i=4;
    int *const ptr=& i; // OK, on initialise ptr pour qu'il prenne l'adresse de i
    int j= 5:
    ptr = &j; // Refusé: on ne peut pas changer l'adresse mémoire vers laquelle
              // pointe ptr
    Et, bien sur, il est possible de déclarer un pointeur constant sur un objet constant (ni l'objet ni le pointeur ne peuvent être modifiés):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int i = 4;
    int const * const ptr= &i; // revient au même que const int * const ptr = &i;
    ++*ptr; // Refusé : l'objet pointé par ptr est constant
    int j =5;
    ptr = &j; // Refusé: on ne peut pas changer l'adresse mémoire vers laquelle
              // pointe ptr
    Alors qu'avec une référence, les choses sont claires: si une référence est déclarée constante, cela signifie:
    1. que l'on ne peut pas modifier l'objet
    2. que l'on ne peut pas décider de se servir de la référence comme alias pour un autre objet.


    Nous en arrivons donc au résultat suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int i = 8;
    int const & ref = i; // revient au même que const int & ref = i; mais en 
                         // respectant la règle générale
    ++ref; // refusé : i est considéré comme étant constant
    int j = 10;
    ref = j; // refusé: ref ne peut pas représenter autre chose que i
    En outre, il faut se souvenir que l'utilisation des pointeurs est énormément associée à la gestion dynamique de la mémoire (création avec new ou new[] et destruction respectivement avec delete ou delete[]), et que la gestion dynamique de la mémoire est le champs de mines par excellence qu'il s'agit d'éviter autant que possible.

    En effet, si tu manipule un pointeur qui pointe vers un objet détruit, tu va envoyer le compilateur "cueillir les marguerites" et tu te retrouvera, toujours trop tard, avec une fantastique erreur de segmentation, et, si tu n'y prend pas gare, tu peux facilement à essayer de libérer la mémoire d'un objet... qui a déjà été détruit, ce qui ne vaut guère mieux

    Or, il faut comprendre que le C++ fournit, au travers des différents conteneurs qu'il présente ou au travers de sa classe string, tout ce qu'il faut pour éviter à l'utilisateur de gérer dynamiquement la mémoire si ce n'est pas tout à fait indispensable.

    Comprenons nous: la gestion dynamique de la mémoire a toujours bien lieu, mais elle se fait de manière tout à fait transparente pour l'utilisateur (comprend: tu n'a pas à t'en occuper toi-même), et souvent de manière bien plus efficace que ce que tu pourrais faire

    Au final, le seul cas où tu dois envisager la gestion dynamique de la mémoire sera celui où tu souhaite manipuler une collections d'objets en les faisant passer pour des objets du type parent (dans le cadre de l'héritage et du polymorphisme).


    Enfin, même si ce n'est qu'un détail, il faut avouer que le fait de garder exactement la même syntaxe lorsque l'on manipule une référence que lorsque l'on manipule l'objet lui-même est presque rassurant:

    Qui n'a jamais "pesté" parce que, ayant oublié qu'il manipulait un pointeur, il s'est fait envoyer sur les roses par le compilateur en ayant utilisé le point plutôt que la flèche

    En conclusion, l'idéal en C++ sera toujours de manipuler des références (éventuellement constantes) partout où c'est possible et de ne manipuler des pointeurs que lorsque l'on n'a vraiment pas le choix
    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

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Février 2008
    Messages
    29
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 29
    Par défaut
    Merci Koala01 pour ta réponse très complète et très utile !

    Et SofEvans tu avais aussi raison, comme moi, sans savoir vraiment pourquoi !

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 633
    Par défaut
    En fait, elle n'est pas encore tout à fait complète, parce que la prochaine norme prévois la mise au point de "rvalue references" dont je n'ai absolument pas parlé jusqu'à présent

    L'astuce, c'est que j'ai moi même le plus grand mal à concevoir une explication qui tienne la route pour l'instant (re )
    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

  6. #6
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par koala01 Voir le message
    En conclusion, l'idéal en C++ sera toujours de manipuler des références (éventuellement constantes) partout où c'est possible et de ne manipuler des pointeurs que lorsque l'on n'a vraiment pas le choix
    Pas d'accord. Je n'arrive pas à considérer que

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void foo(T& t)
    {
       delete &t;
    }
    et meilleur que

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void foo(T* t)
    {
       delete t;
    }
    Commençons par les cas où le pointeur est nécessaire:
    - pour les passages d'argument: quand il faut pouvoir passer NULL
    - pour les variables, quand elles peuvent valoir NULL ou qu'il faut pouvoir modifier l'objet désigné
    Les références elles sont indispensables:
    - pour les arguments modifiables des opérateurs (et parfois pour leurs arguments non modifiables pour des raisons de performances)
    - dans quelques cas imposés par le langage (constructeur de copie par exemple)
    - pour prolonger la durée de vie de temporaires

    J'ai peut-être oublié un cas ou l'autre, mais le choix entre référence et pointeur est effectivement bien souvent un choix purement conventionnel. Et je trouve que la convention "les références quand on peut, les pointeurs quand on doit" est pousser dans le sens des références un peu trop fort.

    Ma pratique?

    D'une part, je fais attention au style du composant utilisé. Mes règles personnelles sont moins importantes que ce respect de la manière dont a été conçu ce que j'utilise. Donc si j'ai à manipuler un type fourni par une bibliothèque, dont toutes les objets sont créés par une factory mais dont toute l'API prend des références -- ce qui est contraire à la manière dont je concevrais --, je ne vais pas transformer assez rapidement le pointeur que j'ai obtenu en créant un objet en une référence.

    Comme paramètre, une référence signifie pour moi que la durée de vie peut être locale à la fonction appelante: on ne la conservera pas au delà du retour de la fonction -- de la durée de vie de l'objet pour un constructeur; on ne contrôlera pas sa durée de vie.

    En général mon choix se fait généralement par types. Les types pour lesquels avoir une variable locale a du sens (valeur, entités du genre IOStream ou RAII) sont passé par référence, les types pour lesquels avoir une variable locale est rare (objets créés uniquement par une factory par exemple) sont passés par pointeur.

  7. #7
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 633
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 633
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Pas d'accord. Je n'arrive pas à considérer que

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void foo(T& t)
    {
       delete &t;
    }
    est meilleur que

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void foo(T* t)
    {
       delete t;
    }
    Je l'admet, mais ton exemple implique que ce qui est transmis sous la forme de t soit à la base un pointeur dont la mémoire est gérée dynamiquement.

    J'aurais effectivement du préciser que, si l'objet à passer en argument est à la base un pointeur (parce que tu n'a pas le choix), il reste logique de continuer à le manipuler sous la forme d'un pointeur dans la fonction appelée...
    Commençons par les cas où le pointeur est nécessaire:
    - pour les passages d'argument: quand il faut pouvoir passer NULL
    - pour les variables, quand elles peuvent valoir NULL ou qu'il faut pouvoir modifier l'objet désigné
    Je rajouterais:
    -pour les variables, lorsque tu as besoin du polymorphisme et que le type de l'objet à créer se détermine selon les circonstances (variable tierce?).

    Mais, comme je l'ai indiqué, ce sont des cas dans lesquels... tu n'a pas le choix, soit du fait des circonstances (la variable d'origine est un pointeur ou tu as un besoin de polymorphisme), soit du fait de la restriction de non nullité imposée par les références

    Les références elles sont indispensables:
    - pour les arguments modifiables des opérateurs (et parfois pour leurs arguments non modifiables pour des raisons de performances)
    - dans quelques cas imposés par le langage (constructeur de copie par exemple)
    sur ces deux points, je suis d'accord, par contre, sur le dernier
    - pour prolonger la durée de vie de temporaires
    j'ai du mal à l'être (à moins que je ne comprenne pas ce que tu as voulu dire):

    Un temporaire étant par définition détruit lorsque l'on sort de la portée dans laquelle il est déclaré, l'utilisation d'une référence en dehors de cette portée aura comme conséquence que la référence est invalide...
    J'ai peut-être oublié un cas ou l'autre, mais le choix entre référence et pointeur est effectivement bien souvent un choix purement conventionnel. Et je trouve que la convention "les références quand on peut, les pointeurs quand on doit" est pousser dans le sens des références un peu trop fort.
    C'est effectivement pousser le bouchon un peu loin, mais, en première approche cela me semble malgré tout être une bonne pratique...

    C'est une règle simple qui, comme toute règle mérite largement d'être affinée, en fonction de situations plus complexes
    Ma pratique?

    D'une part, je fais attention au style du composant utilisé. Mes règles personnelles sont moins importantes que ce respect de la manière dont a été conçu ce que j'utilise. Donc si j'ai à manipuler un type fourni par une bibliothèque, dont toutes les objets sont créés par une factory mais dont toute l'API prend des références -- ce qui est contraire à la manière dont je concevrais --, je ne vais pas transformer assez rapidement le pointeur que j'ai obtenu en créant un objet en une référence.

    Comme paramètre, une référence signifie pour moi que la durée de vie peut être locale à la fonction appelante: on ne la conservera pas au delà du retour de la fonction -- de la durée de vie de l'objet pour un constructeur; on ne contrôlera pas sa durée de vie.

    En général mon choix se fait généralement par types. Les types pour lesquels avoir une variable locale a du sens (valeur, entités du genre IOStream ou RAII) sont passé par référence, les types pour lesquels avoir une variable locale est rare (objets créés uniquement par une factory par exemple) sont passés par pointeur.
    tu as tout à fait raison, mais on est déjà loin de la "première approche" sous tendue par Seabast888 qui est de vouloir savoir la différence entre un pointeur et une référence.

    On reproche souvent aux "gurus" (tous langage confondus, mais principalement en C et en C++) de présenter directement les choses trop en profondeur et, bien que je sois tout à fait d'accord avec toi, tu es peut-être tombé dans cet excès
    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

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

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Par défaut
    Un temporaire étant par définition détruit lorsque l'on sort de la portée dans laquelle il est déclaré, l'utilisation d'une référence en dehors de cette portée aura comme conséquence que la référence est invalide...
    Il faisait référence (c'est le cas de le dire :p) au mécanisme qui fait qu'un temporaire binder à une const référence voit sa durée de vie étendu à celle de la référence?

  9. #9
    Membre confirmé Avatar de sopsag
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 224
    Par défaut
    Si je puis me permettre d'ajouter mon grain de sel, je dirais que le passage par pointeur à l'avantage d'être visible au niveau de l'appel.

    Donc pour augmenter la lisibilité de mon code, j'aime bien passer par pointeur les paramètres susceptibles d'être modifiés durant l'appel.

    Comme ça, quand je vois l'appel foo( bar,&zol ) ; je me dis "tiens, zol peut être modifié par foo..."

    Du coup, mes passages par référence sont souvent const.

    Voila, c'est tout...

  10. #10
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    -pour les variables, lorsque tu as besoin du polymorphisme et que le type de l'objet à créer se détermine selon les circonstances (variable tierce?).
    Rien ne t'empèches d'utiliser une référence (même si ce n'est pas généralement ce que je ferais). Je donnais les cas où le langage ne laisse pas le choix.

    Un temporaire étant par définition détruit lorsque l'on sort de la portée dans laquelle il est déclaré, l'utilisation d'une référence en dehors de cette portée aura comme conséquence que la référence est invalide...
    Un temporaire est détruit à la find de l'expression dans laquelle il a été créé, sauf s'il est bindé à une référence auquel cas sa durée de vie est prolongée pour celle de la référence.

    C'est effectivement pousser le bouchon un peu loin, mais, en première approche cela me semble malgré tout être une bonne pratique...

    C'est une règle simple qui, comme toute règle mérite largement d'être affinée, en fonction de situations plus complexes
    Moi pas. Je l'ai vu trop souvent finir avec delete &ref.

    tu as tout à fait raison, mais on est déjà loin de la "première approche" sous tendue par Seabast888 qui est de vouloir savoir la différence entre un pointeur et une référence.

    On reproche souvent aux "gurus" (tous langage confondus, mais principalement en C et en C++) de présenter directement les choses trop en profondeur et, bien que je sois tout à fait d'accord avec toi, tu es peut-être tombé dans cet excès
    Tu veux une règle simple: ne jamais devoir utiliser l'opérateur &.

    Citation Envoyé par Goten Voir le message
    Il faisait référence (c'est le cas de le dire :p) au mécanisme qui fait qu'un temporaire binder à une const référence voit sa durée de vie étendu à celle de la référence?
    Exact.

    Citation Envoyé par sopsag Voir le message
    Si je puis me permettre d'ajouter mon grain de sel, je dirais que le passage par pointeur à l'avantage d'être visible au niveau de l'appel.
    Un argument dont j'ai toujours eu du mal à voir la portée... j'ai dû faire trop d'Algol, Pascal et autre Ada avant de faire réellement du C++. Ça me semble un argument de quelqu'un qui n'a toujours pas fait la migration depuis le C.

    Comme ça, quand je vois l'appel foo( bar,&zol ) ; je me dis "tiens, zol peut être modifié par foo..."
    Si tu as besoin de ça, c'est que foo est mal nommé et a une fonction mal définie.

    Du coup, mes passages par référence sont souvent const.
    Jamais d'opérateur d'affectation, jamais d'IOStream? :-)

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

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Un temporaire est détruit à la find de l'expression dans laquelle il a été créé, sauf s'il est bindé à une référence auquel cas sa durée de vie est prolongée pour celle de la référence.
    Référence constante, AFAIK, ça ne marche pas avec les références non const.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 633
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Tu veux une règle simple: ne jamais devoir utiliser l'opérateur &.
    Bien vu

    J'ai l'impression que nous sommes encore une fois fondamentalement d'accord sur le principe, mais que nous l'exprimons de manière trop différente pour que cela saute aux yeux

    Et du coup, les deux règles combinées (ne jamais devoir utiliser l'opérateur & et utiliser les références quand tu peux, les pointeurs quand tu n'a pas le choix) expriment clairement la portée du principe que l'on essaye de faire valoir
    Citation Envoyé par sopsag Voir le message
    Si je puis me permettre d'ajouter mon grain de sel, je dirais que le passage par pointeur à l'avantage d'être visible au niveau de l'appel.

    Donc pour augmenter la lisibilité de mon code, j'aime bien passer par pointeur les paramètres susceptibles d'être modifiés durant l'appel.

    Comme ça, quand je vois l'appel foo( bar,&zol ) ; je me dis "tiens, zol peut être modifié par foo..."

    Du coup, mes passages par référence sont souvent const.
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Un argument dont j'ai toujours eu du mal à voir la portée... j'ai dû faire trop d'Algol, Pascal et autre Ada avant de faire réellement du C++. Ça me semble un argument de quelqu'un qui n'a toujours pas fait la migration depuis le C.

    Si tu as besoin de ça, c'est que foo est mal nommé et a une fonction mal définie.
    Je ne peux qu'être d'accord avec Jean Marc...

    La première qualité d'un code (je serais presque tenté de dire "avant même de faire ce que l'on attend de lui" ) est d'être facilement compréhensible par l'humain qui l'a devant les yeux...

    Une grosse part de cette qualité est obtenue en choisissant des identifiants pour ses variables, ses fonctions, ses types personnalisés (et tout le reste) suffisamment explicites pour qu'ils reflètent exactement le but que l'on attend d'eux.

    En plus, ton point de vue ne respecte pas cette fameuse "nouvelle" regle de ne jamais devoir utiliser l'opérateur &

    En poussant ce principe à l'extrême, on pourrait presque estimer que, dans le code suivant, les identifiants i et j pourraient très bien être remplacés respectivement par ligne et colonne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int matrice[3][3];
    for(int i=0;i<3;++i)
        for(int j=0;j<3;++j)
            matrice[i][j]=i*3+j;
    Même si j'admets sans peine que, dans des cas similaires, ce serait peut être pousser le bouchon un peu loin (quoi, que...)
    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
    Membre confirmé Avatar de sopsag
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 224
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet
    Ça me semble un argument de quelqu'un qui n'a toujours pas fait la migration depuis le C.
    Vouaye, c'est pas faux...

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 392
    Par défaut
    @sopsag: En C, on a aussi des pointeurs const et non-const: J'ai pensé comme toi pendant un moment, mais une fois qu'on se met à utiliser les structures comme il faut, l'argument tombe un peu à l'eau...

    Par contre, j'ai tendance à utiliser beaucoup les pointeurs pour des paramètres optionnels (souvent des paramètres en sortie), plutôt que des surcharges de fonction: Quatre paramètres optionnels donneraient 16 surcharges différentes!
    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.

  15. #15
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par koala01 Voir le message
    J'ai l'impression que nous sommes encore une fois fondamentalement d'accord sur le principe, mais que nous l'exprimons de manière trop différente pour que cela saute aux yeux

    Et du coup, les deux règles combinées (ne jamais devoir utiliser l'opérateur & et utiliser les références quand tu peux, les pointeurs quand tu n'a pas le choix) expriment clairement la portée du principe que l'on essaye de faire valoir
    Ma pratique est plus proche de pointeur par défaut et référence quand utiliser un pointeur impliquerait d'utiliser l'opérateur &.

    En poussant ce principe à l'extrême, on pourrait presque estimer que, dans le code suivant, les identifiants i et j pourraient très bien être remplacés respectivement par ligne et colonne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int matrice[3][3];
    for(int i=0;i<3;++i)
        for(int j=0;j<3;++j)
            matrice[i][j]=i*3+j;
    Même si j'admets sans peine que, dans des cas similaires, ce serait peut être pousser le bouchon un peu loin (quoi, que...)
    l et c bien que i et j ne me gène pas du tout. Le principe est que plus la portée est restreinte, plus le nom peut être court.

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

Discussions similaires

  1. Passage de sf::font par référence
    Par sebygames dans le forum SFML
    Réponses: 3
    Dernier message: 14/03/2014, 21h12
  2. Passage d'une matrice par référence
    Par Ulath0 dans le forum R
    Réponses: 2
    Dernier message: 29/09/2009, 22h35
  3. Retour par référence d'un pointeur
    Par FunkyTech dans le forum C++
    Réponses: 16
    Dernier message: 22/07/2008, 13h56
  4. [Tableaux] passage d'une variable par référence
    Par grinder59 dans le forum Langage
    Réponses: 7
    Dernier message: 14/05/2007, 17h52
  5. Passage d'un tableau par référence?
    Par sebduth dans le forum C
    Réponses: 9
    Dernier message: 16/07/2003, 18h32

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