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 :

Const sur argument passé par copie


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti Avatar de Seabirds
    Homme Profil pro
    Post-doctoral fellow
    Inscrit en
    Avril 2015
    Messages
    294
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Post-doctoral fellow
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Avril 2015
    Messages : 294
    Points : 341
    Points
    341
    Par défaut Const sur argument passé par copie
    Salut,

    En lisant un code je suis tombé sur une signature ressemblant a ça:

    int foo(const size_t a, const size_t b)
    Mon premier réflexe a été de me dire que le const devant des arguments passés par copies c’était superflu, mais en allant fouiller j'ai vu qu'il y avait tout un débat la dessus.

    Vous en pensez quoi ?
    Le débutant, lui, ignore qu'il ignore à ce point, il est fier de ses premiers succès, bien plus qu'il n'est conscient de l'étendue de ce qu'il ne sait pas, dès qu'il progresse en revanche, dès que s'accroît ce qu'il sait, il commence à saisir tout ce qui manque encore à son savoir. Qui sait peu ignore aussi très peu. [Roger Pol-Droit]
    Github
    Mon tout premier projet: une bibliothèque de simulation de génétique des populations

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 118
    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 118
    Points : 32 984
    Points
    32 984
    Billets dans le blog
    4
    Par défaut
    Superflu et inutile dans le prototype.
    Dans l'implementation ca peut avoir un interet.
    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.

  3. #3
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    742
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 742
    Points : 3 641
    Points
    3 641
    Par défaut
    Dans l'implémentation, cela garanti que la valeur sera toujours celle d'origine quelle que soit la ligne regardée. Il n'y a plus besoin à se demander si la variable est modifiée puisqu'elle ne le sera jamais. Pour les fonctions de quelques lignes c'est évident, mais beaucoup moins lorsque quelle grossie. Au final, c'est comme toutes les variables constantes.

    Dans un prototype, c'est plus une surcharge visuelle qu'autre chose.

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

    Informations professionnelles :
    Activité : aucun

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

    Je au contraire que c'est parfaitement normal de déclarer un paramètre comme constant et ce quel que soit la manière dont il est transmis (par copie, par référence ou par pointeur).

    En effet la constance doit être envisagée de manière totalement indépendante de la manière à laquelle nous pourrons accéder à la donnée, car elle représente un invariant stricte : la donnée à laquelle nous voulons accéder ne peut pas être modifiée. Et le mieux de l'histoire, c'est que le compilateur pourra gueuler si tu essaye d'ignorer cet invariant.

    Quand on réfléchit à la possibilité de déclarer une donnée comme étant constante, on se fout pas mal de savoir s'il y a eu copie ou non, si on a pris l'adresse de la donnée ou non. On veut juste garantir que la donnée ne sera pas modifiée.

    Avec un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void foo(int const a, int const b);
    on exprimer clairement le fait que foo ne pourra modifier ni a ni b, et le compilateur sera là pour y veiller

    Mieux encore : cela permet de rappeler à celui qui lira le code de foo qu'il ne peut pas essayer de modifier la valeur de a ou de b. S'il doit modifier la fonction foo, il devra prendre cette restriction en compte (et, encore une fois, le compilateur sera là pour veiller à ce qu'il le fasse )

    Pour les types primitifs, ce n'est pas la transmission sous forme de constante qui n'a guère d'intérêt, mais bien la transmission par référence constante plutot que par copie.

    En effet, si l'on observe un peu l'assembleur généré lorsque l'on manipule des références, nous nous rendons compte que c'est l'adresse de la variable qui est utilisée. Et oui, au niveau du processeur, une référence est représentée exactement de la même manière qu'un pointeur!!!

    Ot; une adresse mémoire, ce n'est jamais qu'une valeur numérique entière (généralement non signée) représentée par un nombre de bits au minimum suffisant que pour pouvoir représenter l'ensemble des adresses mémoires auxquelles l'ordinateur a accès.

    Sur les architectures "classiques" de PC, on peut donc estimer que c'est une valeur numérique représentée sur un nombre de bits variant de 32 à 64 (en gros, la taille d'un /* unsigned*/ int ou d'un /* unsigned*/ long long, selon les architectures )

    On se rend donc compte que, s'il faut utiliser 32 ou 64 bits (pour pouvoir représenter l'adresse mémoire d'une donnée qui aurait pu tenir sur "moins que cela" (comme un char ou un short) ou sur "à peu près autant que cela" (comme un int,un long, un long long, un float, un double ou un long double), cela occasionnerait un "fameux gâchis d'espace", car nous pourrions (dans le meilleur des cas) faire passer entre deux et huit valeurs en même temps, et cela sans que la copie ne prenne plus de temps que le fait de transmettre l'adresse mémoire de la donnée.

    C'est pour cela que l'on propose la règle de transmettre par copie tout ce qui "prend moins d'espace mémoire qu'un pointeur" (autrement dit les types primitifs) et par référence (éventuellement constante, si on ne veut pas pouvoir modifier l'objet original) tout ce qui est "plus gros qu'un pointeur". A moins, bien sur, que tu ne veuilles pouvoir modifier la donnée originale (de type primitif) que tu transmet à ta fonction.

    Mais, s'il faut mettre deux choses en oppositions, ce n'est pas le passage par copie et la constante: il faut mettre le passage copie en opposition avec le passage par référence. La constance de la donnée, c'est quelque chose qui n'a strictement rien à voir avec les notions de copie Vs référence Vs pointeur.
    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

  5. #5
    Membre éclairé

    Profil pro
    Inscrit en
    Décembre 2013
    Messages
    397
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2013
    Messages : 397
    Points : 698
    Points
    698
    Par défaut
    Citation Envoyé par koala01 Voir le message
    On veut juste garantir que la donnée ne sera pas modifiée.
    De quelle donnée on parle ?

    L’intérêt de l'interface publique, c'est d'informer l'utilisateur sur comment utiliser la fonction, sans se préoccuper de l’implémentation. Ce qui l’intéresse, c'est de savoir que s'il écrit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int i { 123 };
    int j { 456 };
    foo(i, j);
    ses variables i et j ne seront pas modifiées. Que les paramètres soient const ou non lors d'un passage par valeur ne change rien a cette garantie. Dans les 2 cas, l'appelant sait que ses variables ne sont pas modifiées. De son point de vue, const ne sert a rien.

    Du point de vue ce celui qui va implémenter la fonction, quel est l’intérêt d'avoir une contrainte sur lui, mais qui n'a aucun impact pour les utilisateurs de la fonction ? Pourquoi devoir lui imposer une copie du paramètre const, s'il a besoin de travailler sur cette valeur, alors que le const ne sert a rien ?

    Donc a mon sens : c'est inutile. Ca n'apporte rien a l'utilisateur de la fonction, et c'est une contrainte inutile pour celui qui ecrit la fonction.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 625
    Points : 30 674
    Points
    30 674
    Par défaut
    Citation Envoyé par mintho carmo Voir le message
    De quelle donnée on parle ?
    De n'importe quelle donnée!!!

    Surtout si la donnée est transmise (d'une manière ou d'une autre) à une fonction !!!

    Je vais aborder une notion qui est d'avantage utilisée en programmation fonctionnelle, mais, on se rapproche de l'occasion d'apporter la preuve qu'une fonction est "pure" (quelle ne modifie aucun des arguments qu'elle reçoit en paramètre)
    Citation Envoyé par mintho carmo Voir le message
    L’intérêt de l'interface publique, c'est d'informer l'utilisateur sur comment utiliser la fonction, sans se préoccuper de l’implémentation. Ce qui l’intéresse, c'est de savoir que s'il écrit :
    Et, parce que le code s'adresse aussi bien au développeur qu'au compilateur (faut pas l'oublier, lui ) de permettre au compilateur de s'assurer que les invariants que l'on place sur une donnée (quelle qu'elle soit, quelle que soit la manière dont la fonction l'a reçue) seront respectés.

    Cela s'intègre parfaitement dans une politique qui tend à faire passer le compilateur du statut de "simple outil" (destiné à générer le code binaire exécutable) au statut d'allier (capable de garantir la qualité du code écrit) et qui est exactement la même que celle qui nous incite à déclarer la redéfinition des fonctions virtuelles comme étant override ou même final override
    Citation Envoyé par mintho carmo Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int i { 123 };
    int j { 456 };
    foo(i, j);
    ses variables i et j ne seront pas modifiées. Que les paramètres soient const ou non lors d'un passage par valeur ne change rien a cette garantie. Dans les 2 cas, l'appelant sait que ses variables ne sont pas modifiées. De son point de vue, const ne sert a rien.
    Je t'accorde que cela ne change rien dans la fonction appelante.

    Mais ajouter la constance à un paramètre a pour but d'apporter la garantie dans la fonction appelée (donc dans foo).

    Après, que cette garantie puisse servir à "rassurer" le développeur de la fonction appelante, c'est un autre problème

    Ce que la constance a pour but de garantir, c'est que les valeurs qui sont transmises à foo ne changeront pas, peu importe que ces valeurs aient été transmises par bar, par doSomething ou par main.

    Parce que, lorsque l'on regarde le corps de foo, on sait -- au mieux -- que l'on a reçu deux paramètres de type int, mais on ne peut en aucun cas spéculer sur l'origine de ces deux paramètres.

    En indiquant que foo s'attend à recevoir deux paramètres constant, cela revient -- dans le corps de foo -- à peu près au même que si on avait écrit un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void foo(){
        int const i{35};
        int const j{48};
        /* on peut utiliser i et j, mais on pourra pas les modifier ici */
    }
    A la seule différence que i et j viennent "d'ailleurs" (quand elles sont transmise en argument) parce que la fonction n'est pas en mesure de définir la valeur de ces données.

    Citation Envoyé par mintho carmo Voir le message
    Du point de vue ce celui qui va implémenter la fonction, quel est l’intérêt d'avoir une contrainte sur lui, mais qui n'a aucun impact pour les utilisateurs de la fonction ?
    Que penses tu de la garantie d'avoir affaire à une donnée immuable, qui pourra être controlée par le compilateur :question;

    Pourquoi vas tu t'amuser à écrire un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void bar(){
        const int size{53};
        /* ... */
    }


    Pourquoi la valeur de size devrait elle obligatoirement être connue de la fonction bar

    Pourquoi ne pourrait-elle pas être "définie par ailleurs", et donc, obtenue sous la forme d'un paramètre (ou renvoyée par une fonction à laquelle nous ferions appel)

    En un mot, pourquoi une valeur constante ne pourrait-elle pas être reçue comme paramètre

    Après tout, on le fait régulièrement lorsque l'on transmet des classes et des structure imposantes par référence (dans le but d'en éviter la copie), non

    Cela a -- bien sur -- un attrait du fait même de la mécanique des référence. Mais cela impose aussi des restrictions quant à l'usage que l'on pourra faire de ces données.

    Dés lors, pourquoi serait il "sensé" d'imposer la constance à ce qui est transmis par référence et ... insensé de le faire à ce qui est transmis par copie parce qu'une valeur copiée devra forcément être modifiée Mais il n'y a aucune règle qui l'impose, que je sache !!!

    Bien au contraire! la notion de fonction pure dont j'ai parlé plus tôt nous inciterait justement à faire en sorte de nous assurer que les paramètres reçus sous n'importe quelle forme ne soient jamais modifiés!!!

    Citation Envoyé par mintho carmo Voir le message
    Pourquoi devoir lui imposer une copie du paramètre const, s'il a besoin de travailler sur cette valeur, alors que le const ne sert a rien ?
    Mais, qui te dit qu'il ne doit pas -- justement -- travailler sur une valeur immuable

    Tu semble partir du principe que l'on va forcément vouloir modifier une donnée reçue par copie. Mais il n'y a rien qui t'oblige à le faire!

    Et si tu estimes que la donnée en question doit être immuable, la meilleure chose à faire pour garantir que l'immuabilité sera respectée est encore... de déclarer cette donnée comme constante

    Citation Envoyé par mintho carmo Voir le message
    Donc a mon sens : c'est inutile. Ca n'apporte rien a l'utilisateur de la fonction, et c'est une contrainte inutile pour celui qui ecrit la fonction.
    Nuance : c'est une contrainte potentiellement inutile pour celui qui écrit la fonction. Parce que tu ne vois, pour l'instant, aucune situation dans laquelle elle pourrait se justifier.

    Mais ce n'est pas parce que tu ne vois -- "à l'instant même" -- aucun cas dans lequel cela pourrait se justifier que tu ne seras pas confronté -- dans deux heures ou dans deux ans -- à un cas dans lequel ce sera pleinement justifié.

    Je ne dis nullement qu'il faut en faire une règle générale, mais je dis que tu rencontreras forcément des situations dans lesquelles la fonction que tu dois développer va recevoir des données par copie qu'elle ne pourra pas modifier.

    Et je dis donc seulement qu'il ne faut pas écarter définitivement la possibilité de transmettre un paramètre par copie constante uniquement sous prétexte que l'on ne voit pas pourquoi on le ferait à l'instant même.

    Encore une fois, s'il faut mettre le passage par copie en opposition à "autre chose", c'est au passage par référence et / ou au passage par pointeur. Le problème de la constance des paramètres transmis n'a rien à voir avec la forme sous laquelle on transmet ces paramètres.

    Alors, bien sur, il se fait que, pas de bol, si un paramètre est reçu sous la forme d'une référence ou d'un pointeur, les modifications apportées au niveau de la fonction appelée seront répercutées sur les données qui servent d'argument au niveau de la fonction appelante. Et il se fait que cela rassurera sans doute le développeur de la fonction appelante de savoir que les données transmises comme argument ne seront pas modifiées.

    Mais le problème n'est pas là : le problème est surtout de déterminer précisément ce que la fonction appelée a le droit de faire (ou plutôt, ce qu'elle n'a pas le droit de faire) avec les paramètres qui lui ont été transmis (sous quelle que forme que ce soit).
    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

  7. #7
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 118
    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 118
    Points : 32 984
    Points
    32 984
    Billets dans le blog
    4
    Par défaut
    Mais cela fait plusieurs interventions que je le répète je m'en fous royalement que cela n'apporte rien de plus à l'utilisateur. Ce qui m'importe, c'est ce que cela peut m'apporter à moi, en tant que développeur de la fonction.
    Et moi je m'en bats les cahuets de ce que tu fais dans l'implémentation tant que je sais comment l'utiliser.
    Tu peux répéter une énième fois ta prose, ca n'y changera rien.
    Pourquoi faudrait il écarter une possibilité qui nous permet de profiter de cette rigueur au seul prétexte que "cela n'apporte rien à l'utilisateur"
    Au hasard parce que l'utilisateur est ma cible ?
    Tout comme je pense mon interface publique etc pour lui. Le reste est un détail d'implémentation dont il n'a rien à foutre où je fais ce qu'il faut pour rendre les services voulus et attendus.

    Et même s'il m'arrive de mettre le const dans le prototype pour un paramètre copié, entre autre parce que c'est copié /collé entre header et implémentation, ca n'en reste pas moins absolument inutile.

    Alors pour répondre au message original
    Citation Envoyé par Seabirds Voir le message
    Mon premier réflexe a été de me dire que le const devant des arguments passés par copies c’était superflu
    A raison puisque oui c'est redondant et donc inutile et n'apporte aucune information supplémentaire sur ce que les variables que je passe en paramètre deviennent.

    mais en allant fouiller j'ai vu qu'il y avait tout un débat la dessus.
    Sur internet tout est sujet à débat hélas... Ce sujet ne fait pas exception.
    Mais franchement c'est de l'enculage de mouches
    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. Django: Help view avec un argument passé par une url
    Par 123alban2007 dans le forum Django
    Réponses: 0
    Dernier message: 13/11/2015, 15h21
  2. conteneur passé par copie: reception bizarre.
    Par Krishna dans le forum SL & STL
    Réponses: 2
    Dernier message: 01/03/2009, 20h18
  3. Erreur sur mon constructeur par copie
    Par beegees dans le forum C++
    Réponses: 8
    Dernier message: 02/04/2008, 20h58
  4. Question sur les variables passées par URL
    Par cotlod dans le forum Langage
    Réponses: 7
    Dernier message: 11/10/2006, 00h04
  5. Réponses: 2
    Dernier message: 27/07/2006, 18h50

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