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 :

Argument par référence


Sujet :

C++

  1. #1
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 381
    Points : 19 065
    Points
    19 065
    Par défaut Argument par référence
    Salut à tous.

    En C, nous avons le passage des paramètres par valeur et par adresse.
    En C++, nous avons le passage des paramètres par référence.

    Y-a-t-il une grande différence entre le passage par adresse en C avec le passage par référence en C++ ?

    Selon moi, c'est exactement la même chose.

    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  2. #2
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 648
    Points
    7 648
    Par défaut
    Citation Envoyé par Artemus24 Voir le message
    En C, nous avons le passage des paramètres par valeur et par adresse.
    En C++, nous avons le passage des paramètres par référence.

    Y-a-t-il une grande différence entre le passage par adresse en C avec le passage par référence en C++ ?

    Selon moi, c'est exactement la même chose.
    Plus exactement en C++, nous avons le passage des paramètres par valeur, par adresse, l-référence ou par r-référence.
    Rapidement on a :
    1. par valeur : la fonction reçoit une copie d'un paramètre
    2. par adresse : on passe l'adresse et la fonction reçoit une adresse. Cette adresse peut être nulle, sinon on peut se servir de cette adresse pour accéder à
    3. par l-référence : la fonction reçoit une référence sur une l-value (donc référence à une instance qui une adresse), en aucun cas on ne parle de référence nulle.
    4. par l-référence constante : la fonction reçoit une référence sur un objet quelconque (l-value, x-value ou pr-value), elle ne modifiera pas l'objet. C'est plus puissant que que le passage par adresse d'une constante (capacité de faire du transfert d'owner, possibilité d'accéder à une temporaire créée par conversion.)
    5. par r-référence : la fonction reçoit une référence sur un objet temporaire ou en fin de vie (x-value ou pr-value).
    Même si les 2 cas (b) et (c) peuvent être utilisés pour des choses similaires parfois on n'a pas le choix on ne peut utiliser que le (b), parfois on ne peut utiliser que le (c).

  3. #3
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 381
    Points : 19 065
    Points
    19 065
    Par défaut
    Salut à tous.

    Merci de vos participations.

    Une donnée est une valeur, une adresse est aussi une valeur. Ce qui me fait dire qu'en 'C', on ne sait faire que des passages par valeur.
    Il y a bien recopie, car la fonction (ou la procédure) appelée reçoit dans des registres (je parle du langage assembleur) destiné à cela, ces paramètres.
    Je pense que nous sommes d'accord sur cela en 'C'.

    Qu'en est-il du 'C++' ?' J'ai lu le document.

    Une référence qui est un identificateur à une variable est en fait une autre façon de nommer cette variable.
    Ce qui revient à dire que la référence ou la variable ont la même adresse.

    Qu'est-ce que le passage par référence ?
    Une autre façon d'écrire en 'C++', ce qui est le passage par adresse du 'C'.
    Cela permet de simplifier l'écriture du passage des paramètres en 'C++', qui en 'C' est source d'erreur.

    J'ai fait un test en 'C' et en 'C++' sur le passage des paramètres, à partir de fonctions écrites en assembleur ARM (raspberry pi 4B).
    A ma grande surprise, je n'ai pas constaté de différence entre le passage par référence en 'C++' et le passage par adresse en 'C'. D'où mon sujet !

    Puis-je conclure qu'il n'existe pas de différences entre le passage par adresse en 'C' et le passage par référence en 'C++' ?

    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  4. #4
    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
    En C il n'existe que le passage par copie.
    En C++ le passage par référence évite la copie et passe l'objet original, par quelconque mécanique du compiler.
    Puis les LRValue etc, ce sont d'autres mécanismes du compiler pour déplacer l'objet ou autre.
    Et la question est ? Une fois que tu as les syntaxes, tu as tout. Donc quel est le problème ?
    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.

  5. #5
    Membre éprouvé
    Femme Profil pro
    ..
    Inscrit en
    Décembre 2019
    Messages
    562
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 94
    Localisation : Autre

    Informations professionnelles :
    Activité : ..

    Informations forums :
    Inscription : Décembre 2019
    Messages : 562
    Points : 1 253
    Points
    1 253
    Par défaut
    Salut,

    Citation Envoyé par Artemus24 Voir le message
    Puis-je conclure qu'il n'existe pas de différences entre le passage par adresse en 'C' et le passage par référence en 'C++' ?
    Une référence est un alias, le mécanisme sous-jacent est un pointeur constant auto-déréférençable.

  6. #6
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 381
    Points : 19 065
    Points
    19 065
    Par défaut
    Salut à tous.

    Le mieux est de vous donner mon exemple.

    J'utilise l'assembleur ARM de la raspberry Pi 4B où j'ai créé une fonction et une procédure.
    Dans la fonction ("fval"), je fais un passage par valeur.
    Dans la procédure ("fadr"), je fais un passage par adresse.
    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
            .global fval,fadr
    
    @ ------------------ @
    @ Arguments By value @
    @ ------------------ @
    
            .type   fval,%function
    
    fval:
            .fnstart
            push    {r1-r12,lr}
    
            add     r0,r0,r1
    
            pop     {r1-r12,pc}
            bx      lr
            .fnend
    
    
    @ -------------------- @
    @ Arguments By address @
    @ -------------------- @
    
            .type   fadr,%function
    
    fadr:
            .fnstart
            push    {r0-r12,lr}
    
            ldr     r0,[r0]
            ldr     r1,[r1]
    
            add     r3,r0,r1
    
            str     r3,[r2]
    
            pop     {r0-r12,pc}
            bx      lr
            .fnend
    En rouge, la partie qui effectue l'addition.

    J'utilise un programme écrit en 'C', pour tester la fonction et la procédure.
    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <inttypes.h>
     
    extern int  fval(int ,int );
    extern void fadr(int*,int*,int*);
     
    int main(void)
    {
            int a=2,b=-3,c=0;
            int x=4,y=+5,z=0;
     
            c=fval( a ,b);          /* Function  */
              fadr(&x,&y,&z);       /* Procedure */
     
            printf("val : %2d + %2d = %2d\n", a, b, c);
            printf("adr : %2d + %2d = %2d\n", x, y, z);
     
            exit(EXIT_SUCCESS);
    }
    A l'exécution, j'obtiens bien le résultat attendu :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    > ./prm_c
    val :  2 + -3 = -1
    adr :  4 +  5 =  9
    >
    J'utilise ensuite un programme écrit en "C++" pour tester la même fonction et la même procédure.
    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
    #include <iostream>
    #include <iomanip>
     
    using std::cout;
    using std::endl;
    using std::setw;
     
    using namespace std;
     
    extern "C" int  fval(int ,int);
    extern "C" void fadr(int&,int&,int&);
     
    int main(void)
    {
            int a=2,b=-3,c=0;
            int x=2,y=+6,z=0;
     
            c=fval(a,b);    /* Function  */
              fadr(x,y,z);  /* Procedure */
     
            cout << "val : " << setw(2) << a << " + " << setw(2) << b << " = " << setw(2) << c << endl;
            cout << "adr : " << setw(2) << x << " + " << setw(2) << y << " = " << setw(2) << z << endl;
     
            return 0;
    }
    A l'exécution, j'obtiens le résultat attendu :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    > ./prm_cpp
    val :  2 + -3 = -1
    adr :  2 +  6 =  8
    >
    Dans le cas de la procédure ("fadr"), j'ai utilisé la syntaxe 'C' pour le passage des paramètres par adresse.
    J'ai utilisé la syntaxe 'C++' pour le passage des paramètres par référence.
    Dans les deux cas, c'est la même procédure.

    D'où la question de mon premier message :
    Citation Envoyé par Artemus24
    Y-a-t-il une grande différence entre le passage par adresse en C avec le passage par référence en C++ ?
    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  7. #7
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Ta question concerne la sémantique dans le langage ou l'implémentation en assembleur de ces sémantiques ?

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

    Informations professionnelles :
    Activité : aucun

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

    En fait, tout ce que tu dois te dire, c'est que les mécanismes internes du C++ sont là pour, justement, éviter de te faire faire des noeuds dans tes neurones car on a
    • le passage par valeur
    • le passage par pointeur / adresse
    • le passage par référence, pouvant être
      • lvalue reference
      • rvalue reference

    SI tu descend au niveau de l'assembleur, tu n'auras plus beaucoup de choix car le passage de paramètre se fera automatiquement par valeur (et donc par copie de la valeur transmise, à tout le moins, d'une adresse mémoire donnée à un registre, quelconque ou l'inverse).

    Le fait est que cette valeur peut représenter, en fonction de l'instruction appelée:
    • soit une valeur numérique "normale" (153, 3.145926, 'd',...)
    • soit une adresse mémoire
    • soit le décalage mémoire entre une adresse mémoire de base et l'adresse à laquelle se trouve la donnée à laquelle tu veux accéder.

    Tu peux donc en arriver à la conclusion que tu n'utilises -- au mieux -- que des pointeurs et de "ptrdiff" lorsque tu te retrouve à manipuler l'assembleur

    Mais ca, j'ai envie de dire que l'on s'en fout!!!

    L'assembleur est un langage dit "de deuxième génération" (basé sur les mnémoniques) alors que C et C++ sont déjà des langages dits "de troisième génération" (ou "proche du langage humain).

    Vouloir comparer les deux revient en quelque sorte au même que si tu voulais comparer une scie à main à une tronçonneuse: les deux vont fournir un service sensiblement identique (celui de couper le bois), seulement l'une existe depuis des siècles et nécessite une bonne dose de sueur alors que l'autre est "relativement récente" et demande beaucoup moins d'effort à celui qui la manipule.

    Il en va de même de la différence entre C et C++: Tous les deux ont beau être des langages dits "de troisième génération" il arrivent malgré tout à "s'écarter" de l'aspect purement matériel de l'assembleur de manière tout à fait différente.

    Cela revient donc à comparer une 2CV -- voiture mythique s'il en est -- sans synchronisation de la boite de vitesse, sans direction assistée et encore moins d'air bag ou d'ABS à une voiture "bas de gamme" actuelle: tu as bel et bien deux voitures l'une en face de l'autre, mais la facilité de conduite, la sécurité et le confort sont ... sans communes mesures.

    Il faut en effet comprendre que C a été développé ... "longtemps" avant que C++ ne soit développé, et que, au moment où Denis et Ritchie ont développé le C, il était encore "assez difficile" de s'abstraire de la notion d'adresse mémoire, si bien que la capacité de modifier effectivement la valeur d'un paramètre passé à une fonction a été fournie en créant la notion de "pointeur", qui n'est rien d'autre que l'adresse mémoire à laque on est sensé trouver la donnée qui nous intéresse (notion qui était déjà connue en assembleur).

    Cependant, cette notion de pointeur oblige malgré tout le développeur à se poser énormément de questions dont il n'a pas forcément la réponse si l'on ne peut pas garantir le respect de certaines spécifications très particulières.

    Presque toutes ces questions portent essentiellement sur un point bien précis: qui a le droit "de vie et de mort" de la donnée qui se trouve à l'adresse mémoire indiquée

    Parmi ces questions, on trouve, entre autres:
    • Est-ce que je dois libérer la mémoire qui se trouve à l'adresse indiquée par le pointeur
    • Est-ce que l'adresse mémoire indiquée est bel et bien valide ( différente de NULL / nullptr)
    • Est-ce que "quelqu'un d'autre" que la fonction sur laquelle je travaille va s'occuper de libérer l'adresse mémoire sur laquelle je travaille ou est-ce qu'il faut que je le fasse moi-même (si tant est que cela doive être fait)
    • j'en passe, et sans doute de meilleures.

    Si C++ a gardé le concept de pointeur pour des raisons de compatibilité, il faut se rappeler qu'il a été développé ... "longtemps" après C, et que, à ce moment là, il était déjà "facile" de s'écarter "un peu plus" de l'assembleur qu'avec C.

    Il a --entre autres -- été développé en se disant quelque chose comme
    Si j'arrive à cacher le fait que c'est de toutes façons l'adresse de la donnée qui est transmise comme paramètre à la fonction, mais que j'arrive à garantir le fait que la donnée transmise existe bel et bien et, surtout qu'elle continue à exister après l'exécution de la fonction, je devrais arriver à éviter bien des interrogations à la personne qui s'occupe de développer la fonction en question
    A partir de cette réflexion, la notion de référence est apparue, avec quelques aspects particulièrement sympas, parmi lesquels on peut citer:
    • le fait que l'on peut transmettre les données par référence exactement comme s'il s'agissait des données elles-mêmes (plus besoin d'aller chercher l'adresse de la donnée que l'on veut transmettre)
    • le fait que l'on peut manipuler une donnée transmise par référence exactement comme s'il s'agissait de la donnée elle-même (plus besoin d'aller chercher "ce qui est pointé par" le pointeur manipulé)
    • le fait que l'on n'a plus besoin de se demander si la donnée existe bel et bien, car elle existe d'office (plus besoin de tester le pointeur pour savoir s'il est égal à NULL / nullptr)
    • le fait que l'on n'a plus besoin de se demander s'il faut veille à libérer la mémoire utilisée par la donnée pointée (la donnée existe avant la fonction et après la fonction, il n'y a aucune raison pour qu'elle cesse d'exister pendant la fonction)
    • j'en passe, et sans doute de meilleures

    Alors, oui, bien sur! Toutes ces facilités n'existent finalement qu'au niveau de C++, car, dés que l'on observe un tant soit peu l'assembleur qui sera généré, nous nous rendons compte que nous retombons sur l'éternelle transmissions par adresse.

    Mais, l'un dans l'autre, on s'en tout pas mal et ce, quel que soit le sens dans lequel on regarde car, si toutes ces garanties "disparaissent' (au même titre que les noms de type, de fonctions et de variables) en assembleur, bah, ce n'est pas bien grave car elles ont joué leur rôle pour la personne qui lit le code écrit en C++

    D'un autre coté, si "quelqu'un" venait à lire le code assembleur généré en sachant que le pointeur auquel il est confronté est en réalité issu de l'utilisation d'une référence, il peut parfaitement partir du principe que ces garanties sont bel et bien présentes, vu qu'elles l'étaient dans le code originel
    Citation Envoyé par Artemus24 Voir le message
    D'où la question de mon premier message :
    Citation Envoyé par Artemus24
    Y-a-t-il une grande différence entre le passage par adresse en C avec le passage par référence en C++ ?
    @+
    Et la réponse est toute simple, bien qu'il s'agisse d'une réponse de normand

    Car la réponse est oui, il y a une très grande différence entre le passage par adresse du C et le passage par référence, cependant, cette différence n'est pas visible en terme du binaire généré (ni même de l'assembleur généré), et ce n'est sans doute pas cette différence que tu penseras en premier lieu:

    Car les vraies différences qu'il y a entre les deux résident dans
    • la facilité de manipulation: tu manipule les références exactement comme s'il s'agissait des données d'origine
    • la garantie de validité de la donnée: tu ne dois pas t'inquiéter de savoir si la donnée existe bel et bien car tu as la garantie que c'est le cas
    • le fait que la réponse à la question "dois-je libérer la mémoire allouée à cette donnée " est claire et définitive: non, "quelqu'un" (ou "quelque chose") s'en chargera pour toi après l'exécution de ta fonction

    Si bien que l'un des conseils les plus fréquemment donné est:
    Utilises les références (éventuellement constantes) pour tout élément "plus gros qu'un type primitif" à chaque fois que c'est possible.
    n'utilises les pointeurs que lorsque tu n'as vraiment pas d'autre choix
    Or, il se fait que tu n'auras sans doute pas d'autre choix que dans un seul cas sommes toutes assez particulier qui a systématiquement trait à l'héritage et au polymorphisme; principalement lorsqu'il s'agit de maintenir plusieurs instances d'objets polymorphes dans une même collection dans l'idée de les manipuler "comme s'il s'agissait du type de base".
    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

  9. #9
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 471
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 471
    Points : 6 110
    Points
    6 110
    Par défaut
    Citation Envoyé par Artemus24 Voir le message
    Y-a-t-il une grande différence entre le passage par adresse en C avec le passage par référence en C++ ?

    Selon moi, c'est exactement la même chose.
    Sémantiquement, un pointeur est une adresse qui peut être nulle, tandis qu'une référence est une adresse toujours non nulle.

    Dans des programmes en langage C, on peut voir des bouts de codes ennuyeux du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    assert(parameter != NULL);
    ou, pire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    if (parameter == NULL)
        return;
    En C++, dans ce genre de cas, au lieu de choisir un paramètre de type pointeur, on choisit un paramètre de type référence.

    EDIT : ah, koala01 a répondu entre temps.
    Citation Envoyé par koala01 Voir le message
    le fait que l'on n'a plus besoin de se demander si la donnée existe bel et bien, car elle existe d'office (plus besoin de tester le pointeur pour savoir s'il est égal à NULL / nullptr)
    Le C++ ne garantit pas qu'une référence n'est pas une dandling reference. Par contre, on n'a effectivement pas à tester qu'une référence est non nulle.

  10. #10
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 648
    Points
    7 648
    Par défaut
    La question est dans mot "grande".
    Si on s'interresse au code généré, il existe des tas de cas où c'est similaire. Il peut y avoir des cas où le code sera plus optimisé si on utilise une référence, car par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    inline check42( int* adrval ) {
        if ( adrval )
            return  false;
        return  *adrval == 42;
    }
    void process( int& item ) {
        if ( check42( &item ) )
            std::cout << "the item is 42\n";
    }
    Dans ce code si la fonction process() est définie comme recevant une référence, l'assembleur va immédiatement simplifier. Si l'interface de la fonction est par pointeur on aura plus de code généré.
    On peut dire que le code généré sera toujours plus optimum avec une référence (on a une information de plus que l'objet existe forcément.)

    Si maintenant on s'interesse à la sémantique, là c'est plus le codeur qui va y gagner en utilisant un passage par référence. Moins de confusion pour dissocier l'utilisation du pointeur de l'utilisation du pointé. Certitude que l'on référence bien quelque chose.

    Donc on peut dire qu'il n'a que des avantages à utiliser un passage par référence. De là à dire que c'est une "grande" différence, c'est peux être au choix de chacun.

    Maintenant si on s'interesse aux références comme valeur de retour de fonction ou comme variables locales comme par exemple dans :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for ( auto&& item : collection )
        item++;
    Là l'avantage des références par rapport aux pointeurs commence à se creuser un peu plus. On peut alors parler de "grande" différence.
    Il doit y avoir des exemples plus simple et plus marquant.

  11. #11
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 381
    Points : 19 065
    Points
    19 065
    Par défaut
    Salut à tous.

    Citation Envoyé par Bktero
    Ta question concerne la sémantique dans le langage ou l'implémentation en assembleur de ces sémantiques ?
    Je ne vais pas répéter une troisième fois ma question.

    [quote="koala01"]Si tu descends au niveau de l'assembleur, tu n'auras plus beaucoup de choix car le passage des paramètres se fera automatiquement par valeur (et donc par copie de la valeur transmise, à tout le moins, d'une adresse mémoire donnée à un registre, quelconque ou l'inverse).
    Dois-je comprendre que si je change de langage, j'aurai d'autres choix que le passage des paramètres par valeur ou par adresse ?

    Citation Envoyé par koala01
    Toutes ces facilités n'existent finalement qu'au niveau de C++, car, dés que l'on observe un tant soit peu l'assembleur qui sera généré, nous nous rendons compte que nous retombons sur l'éternelle transmissions par adresse.
    C'est cette affirmation que je recherchais car je me demandais si le passage des paramètres en assembleur était conforme au langage 'C++'.
    Au niveau de la compilation 'C++' et de l'exécution, je n'ai pas eu d'erreurs.

    Je me demande s'il existe un autre façon de procéder en assembleur, pour le passage des paramètres vers le 'C++' ? Je pense que la réponse est non.

    Je dois comprendre que ce sont des mécanismes du compilateur 'C++' dont la vocation est de simplifier, ce qui était genre usine à gaz en 'C'.
    Qu'il y a des sécurités en 'C++' pour garantir la conformité, mais qu'au niveau de l'assembleur, on s'en fout, tant qu'on n'enfreint pas quelques règles de bon sens.

    Merci koala01 pour tes explications.

    Citation Envoyé par Pyramidev
    Sémantiquement, un pointeur est une adresse qui peut être nulle, tandis qu'une référence est une adresse toujours non nulle.
    Pour le passage des paramètres, je n'aurai jamais une adresse nulle, car cela n'aurai aucun sens.
    Mais dans ls deux cas, cela reste une adresse.

    Citation Envoyé par Pyramidev
    Le C++ ne garantit pas qu'une référence n'est pas une dandling reference.
    Je ne connais pas cette notion.
    Après recherche, j'ai découvert que : "Une dandling reference (référence pendante) est une référence à un objet qui n'existe plus".
    Je ne suis pas dans ce cas là, car je ne désalloue pas la mémoire de cet objet, même en assembleur.

    Citation Envoyé par dalfab
    Donc on peut dire qu'il n'a que des avantages à utiliser un passage par référence.
    J'ai bien compris le bénéfice de cette approche.

    Merci à tous.
    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Pyramidev Voir le message
    Le C++ ne garantit pas qu'une référence n'est pas une dandling reference. Par contre, on n'a effectivement pas à tester qu'une référence est non nulle.
    Et encore, je ne vois personnellement que deux cas susceptibles de provoquer l'apparition d'une dandling reference:


    Soit, on a une fonction qui est sensée renvoyer une référence, et la logique fait que c'est une référence sur une donnée temporaire qui est renvoyée, ce qui est le symptôme même d'un problème de logique ou à tout le moins d'inadéquation de la logique par rapport au but de la fonction.

    Soit, nous sommes dans un contexte multi threadé, et nous avons une fonction qui est "un peu trop pressée" de supprimer une donnée

    Dans le premier cas, un compilateur correctement régler devrait signaler très clairement le problème
    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
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 471
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 471
    Points : 6 110
    Points
    6 110
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Soit, on a une fonction qui est sensée renvoyer une référence, et la logique fait que c'est une référence sur une donnée temporaire qui est renvoyée, ce qui est le symptôme même d'un problème de logique ou à tout le moins d'inadéquation de la logique par rapport au but de la fonction.

    Soit, nous sommes dans un contexte multi threadé, et nous avons une fonction qui est "un peu trop pressée" de supprimer une donnée
    Il y a aussi le cas d'une référence vers un élément d'un vecteur. Si le vecteur grandit jusqu'à dépasser sa capacité et que les éléments sont déplacés ailleurs en mémoire, alors la référence précédente n'est plus valide et ne doit plus être utilisée. Mais le langage C++ n'empêchera pas un développeur étourdi de déréférencer ladite référence invalide.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Pyramidev Voir le message
    Il y a aussi le cas d'une référence vers un élément d'un vecteur. Si le vecteur grandit jusqu'à dépasser sa capacité et que les éléments sont déplacés ailleurs en mémoire, alors la référence précédente n'est plus valide et ne doit plus être utilisée. Mais le langage C++ n'empêchera pas un développeur étourdi de déréférencer ladite référence invalide.
    Ah oui, tiens, je l'avais oublié celle-là...

    Quoi qu'il en soit, c'est encore une fois le symptome qu'il y a un cheveu dans la soupe et que "quelque chose" s'amuse à garder une référence beaucoup plus longtemps qu'il ne le devrait...
    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

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Artemus24 Voir le message
    Dois-je comprendre que si je change de langage, j'aurai d'autres choix que le passage des paramètres par valeur ou par adresse ?
    Excuses moi, ta question était quelque peu passé au bleu en ce qui me concerene...

    Non, ce que tu dois comprendre, c'est que tu n'auras pas d'autre choix que de transmettre des paramètre par valeur ou par adresse si tu descend au niveau de l'assembleur, voire, du langage binaire qui sera exécuté.

    Autrement dit, cette restriction n'existe que pour les langages de première et de deuxième génération (le langage machine et l'assembleur).

    Dés que tu t'intéressera à un langage dit "de troisième génération", les possibilités qui te sont données dépendront exclusivement de l'optique, de la philosophie du langage que tu étudie, et cela peut varier énormément:
    • C t'autorise le passage par valeur et par adresse (comme l'assembleur)
    • C++ t'autorise le passage par valeur, par adresse et par référence
    • java ne t'autorise que le passage par référence (ou par adresse voilà que je suis pris d'un doute )
    • d'autres langages ont sans doute d'autres philosophie qui leur sont propres


    C'est cette affirmation que je recherchais car je me demandais si le passage des paramètres en assembleur était conforme au langage 'C++'.
    Non, et, l'un dans l'autre, ils n'ont pas à l'être, car le compilateur est, justement, là pour faire la transition entre le C++ (langage de troisième génération) et l'assembleur (langage de deuxième génération).
    Je me demande s'il existe un autre façon de procéder en assembleur, pour le passage des paramètres vers le 'C++' ? Je pense que la réponse est non.
    Le passage de l'assembleur vers le C++ n'est vraiment pas ce qui se fait de la manière la plus courante.

    D'habitude, ce sera plutôt le passage du C++ vers l'assembleur qui sera privilégié

    On pourrait même, si on était un tant soit peu suspicieux, s'interroger sur les raisons qui te pousseraient à faire l'inverse, voire, carrément mettre en doute la légalité de tes intensions

    Cependant, pour malgré tout répondre à ta question, il faut bien te dire que, comme il n'existe aucune différence (en assembleur) entre un argument utilisé sous forme d'adresse issus de la transmission d'un pointeur et un argument utilisé sous forme d'adresse issus de la transmission d'une référence, il est très difficile de déterminer dans quelle situation tu est dans le premier cas et dans quelle situation tu est dans le deuxième.

    Si le développeur place des assertions sur les pointeurs qu'il utilise et que tu utilise l'assembleur généré en mode Debug, tu pourrais sans doute repérer ces assertions et donc avoir la certitude que tu travailles avec des pointeurs.

    Par contre, à moins de faire une analyse sur l'ensemble du processus subit par l'argument observé (comprends: de vérifier tous les accès qui sont effectués sur la donnée transmise depuis qu'elle a été déclarée et jusqu'à ce qu'elle soit transmise à la fonction que tu étudie), il sera sans doute très difficile de déterminer avec certitude que l'argument a bel et bien été transmis par référence.

    Et comme certaines structures (transmises par référence) peuvent très facilement avoir besoin de l'allocation dynamique de la mémoire en interne (faisons simple: je parle de l'ensemble des collections proposées par la bibliothèque standard, à l'exclusion uniquement de std::array ) le risque d'avoir un "faux pointeur avéré" positif parce que l'on arrive à repérer un élément de gestion dynamique de la mémoire reste malgré tout très important

    Je dois comprendre que ce sont des mécanismes du compilateur 'C++' dont la vocation est de simplifier, ce qui était genre usine à gaz en 'C'.
    Qu'il y a des sécurités en 'C++' pour garantir la conformité, mais qu'au niveau de l'assembleur, on s'en fout, tant qu'on n'enfreint pas quelques règles de bon sens.
    Tu dois surtout comprendre que le compilateur et toi formez véritablement une équipe qui travaille dans un but commun et partagé; que, s'il est normal que le compilateur te fasse confiance pour définir au mieux de tes capacités les instructions qui devront être exécutées en vue d'atteindre l'objectif, il est en retour tout à fait logique que tu lui fasse confiance pour traduire ces instructions, sans trahir ton raisonnement, en respectant l'intention que tu auras décrite

    PROMOTION PERSO="ON"
    Je ne sais pas si tu as lu le livre que j'ai écrit, mais il contient tout un chapitre nommé "Mon pote, le compilateur", dans lequel je dis (en substance) que le compilateur est peut-être un grand bavard, mais que ce qu'il me dit est souvent particulièrement sensé
    PROMOTION PERSO="OFF"
    Pour le passage des paramètres, je n'aurai jamais une adresse nulle, car cela n'aurai aucun sens.
    Hummm... je ne serais pas forcément aussi catégorique que toi sur ce coup là, car, en fait, tout dépend de la raison d'être du paramètre...

    Il arrive en effet "régulièrement" que tu souhaites permettre à l'utilisateur de transmettre un paramètre qui pourrait "tout aussi bien" ne pas exister.

    Dans ce genre de situation, tu serais donc sans doute appelé à demander à ce que le paramètre en question soit un pointeur qui pourrait potentiellement être nul pour indiquer l'inexistence de la donnée demandée, et qui devrait donc forcément être testé avant de faire quoi que ce soit d'autre à partir de lui

    Bien sur, on dispose (depuis C++17) de std::optional, qui pourrait s'avérer très intéressant dans certains cas, cependant, cette possibilité n'est pas forcément adaptées à ** toutes ** les situations
    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

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

Discussions similaires

  1. Réponses: 7
    Dernier message: 07/06/2019, 17h00
  2. Passage d'argument par référence (String et StringBuffer)
    Par dword2add dans le forum Débuter avec Java
    Réponses: 9
    Dernier message: 18/03/2008, 16h50
  3. Conteneurs STL : passage d'arguments par référence
    Par bolhrak dans le forum SL & STL
    Réponses: 0
    Dernier message: 26/09/2007, 20h54
  4. Passage d'arguments par référence
    Par Xavier44214 dans le forum Langage
    Réponses: 5
    Dernier message: 12/04/2007, 14h08
  5. [POO] Argument facultatif par référence
    Par windob dans le forum Langage
    Réponses: 11
    Dernier message: 20/08/2006, 15h02

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