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 :

reference sur double


Sujet :

C++

  1. #1
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2012
    Messages
    538
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2012
    Messages : 538
    Points : 262
    Points
    262
    Par défaut reference sur double
    Bonjour,

    J'ai une classe A :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class A {
        private:
            double _d;
     
        public:
            A(double a) { _d = a }
            A(const double & a); { _d = a; }
    };
    Lequel des deux constructeurs et le plus rapide ?

    Merci.

  2. #2
    Expert éminent sénior

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

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Aucun, les deux seront compilés de la même manière la plus optimale, vu qu'il s'agit d'un type primitif, sauf sur une architecture mal fichue.

    Cela, grâce à la règle du "as if", qui dit qu'un compilateur peut faire ce qu'il veut, tant que tu ne vois pas la différence avec les exigences de la norme.

    De toute façon, le plus rapide sera normalement le suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    A(double const& a) : _d(a) {}
    Ce constructeur aura lui l'avantage de ne pas initialiser _d avant de le réaffecter.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  3. #3
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2012
    Messages
    538
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2012
    Messages : 538
    Points : 262
    Points
    262
    Par défaut
    dans ce cas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int fonction() { return 2;}
     
    int main() {
       int a = function();
       int & b = function();
    }
    b est plus rapide que a ? on évite une recopie ?

  4. #4
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    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 : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    Ça ne compilera pas car une référence ne peut pas être initialisée avec une rvalue (mais une référence constante si (allongement de la durée de vie et des problèmes si mal utilisée)).
    Mais sinon, le compilateur optimisera avec une élision (voir RVO).

  5. #5
    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 CliffeCSTL Voir le message
    dans ce cas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int fonction() { return 2;}
     
    int main() {
       int a = function();
       int & b = function();
    }
    b est plus rapide que a ? on évite une recopie ?
    Ca, c'est tout un programme, qui dépendra essentiellement de la signature complete de function et de l'origine de la valeur qu'elle renvoie...

    De manière générale : si function renvoie une valeur, nous avons la certitude que int a = function() fonctionnera, par contre, int & b = function() aura un problème car b sera une référence invalide (car la durée de vie de la variable renvoyée par function ne sera pas élargie à une variable déclarée dans la fonction appelante).

    D'un autre coté, function pourrait renvoyer une référence. Mais il faut alors voir quelle est l'origine de la variable qui est renvoyée par référence. S'il s'agit d'une référence sur une variable propre à function proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    double /*const*/ & function(){
        double d;
        /* ... */
       return d; // oupppssss...
    }
    les deux codes poseront problèmes car la référence est invalidée par la destruction de la variable qui survient lorsque l'on quitte la fonction.

    Par contre, si la référence renvoyée est issue "d'ailleurs" sous une forme qui pourrait être proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    double & function (double & d){
        /* ... */
        return d;
    }
    on pourra avoir quelque chose de valide aussi bien pour la valeur a que pour la référence b. Et, a priori, b sera alors plus rapide parce qu'il n'y a pas copie.

    Par contre, il n'y a pas de sens à s'inquiéter des éventuelles pertes de performances dues à la copie d'une variable de type primtif par rapport au passage par référence, car il n'y a aucun avantage mesurable (la copie des type primitifs est très rapide, et une référence est représentée au niveau du code exécutable, par une adresse, qui devra de toutes façon être donnée et qui prendra autant de temps à être écrite en mémoire que ce qu'un double peut nécessiter pour être copié).

    L'idée est donc, pour les types primitifs et / ou les structures dont la taille est plus petite qu'un ptr_t, de les manipuler systématiquement par valeur, sauf s'il s'agit de les transmettre à une fonction qui devra modifier la valeur d'origine et, à ce moment là, de les passer par référence non constante.

    Pour les types de taille plus importante, la règle est de les transmettre systématiquement par référence et de rendre la référence constante si la variable d'origine ne doit pas être modifiée par la fonction appelée.

    Par contre, lorsqu'il s'agit de renvoyer ces donnée en sortie de fonction, il faudra s'assurer que la durée de vie de l'élément renvoyé sera suffisante. Ce parfois le cas, parfois pas

    Citation Envoyé par jo_link_noir Voir le message
    Ça ne compilera pas car une référence ne peut pas être initialisée avec une rvalue (mais une référence constante si (allongement de la durée de vie et des problèmes si mal utilisée)).
    Mais sinon, le compilateur optimisera avec une élision (voir RVO).
    Justement, non, cela compilera...

    L'élément renvoyé par une fonction est systématiquement une... lvalue . Les deux possibilités compileront donc et les deux possibilités subiront éventuellement les mêmes problèmes en fonction de ce qui est réellement renvoyé par function
    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 é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 koala01 Voir le message
    Justement, non, cela compilera...

    L'élément renvoyé par une fonction est systématiquement une... lvalue . Les deux possibilités compileront donc et les deux possibilités subiront éventuellement les mêmes problèmes en fonction de ce qui est réellement renvoyé par function
    Au temps pour moi, je dis une énormité.

    double & b = function(); compilera bien, pour autant que la const-correctness soit respectée. La raison en est que le compilateur sait se trouver à droite de l'opérateur d'affectation et qu'il s'attend donc à trouver... une rvalue (qui, basiquement, signifie "quelque chose susceptible de prendre place à droite de l'opérateur d'affectation" ).

    La valeur renvoyée par une fonction peut, quoi qu'il arrive, effectivement prendre place à droite de l'opérateur d'affectation et le compilateur n'a donc aucune raison de refuser cette affectation.

    Par contre, le fait que le code compile ne signifie absolument pas qu'il s'exécutera sans problème . Et le fait est que le compilateur ne dispose que de la signature de la fonction appelée pour se faire un idée de "ce qui fonctionnera" et de "ce qui n'ira pas".

    Le problème, c'est que ce n'est pas assez pour pouvoir se faire une idée . Il y a en effet trois solutions :
    • La fonction renvoie une valeur : le compilateur pourrait éventuellement nous indiquer que nous affectons un temporaire à notre référence. Mais il ne le fera que sous la forme d'un avertissement.
    • La fonction renvoie une de ses variables propres sous la forme d'une référence : la référence est invalide, le compilateur peut indiquer que la fonction appelée renvoie une référence sur un temporaire, mais ce n'est encore qu'un avertissement.
    • La fonction renvoie un argument qu'elle a reçu sous la forme d'une référence ou un membre de la classe au départ duquel la fonction a été appelée : il n'y a aucun problème et tout va bien... Si ce n'est que c'est le genre d'information qui nécessiterait l'analyse du code de la fonction appelée pour pouvoir s'en assurer. Et le compilateur n'est, a priori, pas équipé pour faire cette vérification au niveau de la fonction appelante

    Donc, oui, il y a toujours un manque de garantie quant au fait que la référence soit bel et bien valide, mais cela n'occasionnera, au mieux, qu'un avertissement de la part du compilateur avec comme résultat le fait que seule des options de compilations particulièrement strictes (je pense, par exemple, à l'option -werror sous gcc) occasionneront réellement une erreur de compilation
    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
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2012
    Messages
    538
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2012
    Messages : 538
    Points : 262
    Points
    262
    Par défaut
    Donc j'ai bien le droit de faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    (const?) objet & A = construire_objet();
    int value = A.get_value();
    Comme j'ai le droit de faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int value = construire_objet().get_value();

  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
    La réponse tient en deux mots : oui mais

    Oui, tu as le droit de le faire dans le sens où le compilateur n'y verra aucune objection.

    Mais, pour que A soit une référence valide, il faut:
    • que construire_objet() renvoie une référence
    • que la référence renvoyée par construire_objet fasse référence à un objet qui continue à exister en dehors de cette fonction (autrement dit, que la référence renvoyée par construire_objet() soit valide)

    Et ça, c'est très loin d'être gagné

    Il est possible de se donner les moyen de garantir que ce sera le cas (en plaçant l'objet créé dans une collection dont on sait qu'elle continuera d'exister en dehors de construire_objet, par exemple), mais, de manière générale, il faut vraiment voir ce que fait exactement la fonction appelée (construire_objet() en l'occurrence) pour pouvoir te dire si la référence renvoyée par cette fonction est valide ou non.

    On va donc dire : on peut le faire (c'est légal en C++), mais, a priori, il y a de fortes chances pour que cela pose problème (du moins, sans avoir un exemple précis de ce que fait la fonction appelée pour initialiser ta référence-
    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

Discussions similaires

  1. Réponses: 3
    Dernier message: 04/10/2005, 15h39
  2. Pb reference sur une globale inutilisée (VC6)
    Par symmenthical dans le forum MFC
    Réponses: 1
    Dernier message: 11/05/2005, 21h35
  3. Probleme heritage : References sur la table parente
    Par Belgar dans le forum PostgreSQL
    Réponses: 3
    Dernier message: 03/05/2005, 22h11
  4. Question sur double click
    Par cjacquel dans le forum MFC
    Réponses: 2
    Dernier message: 30/04/2005, 11h53
  5. reference sur un objet
    Par romeo9423 dans le forum C++
    Réponses: 5
    Dernier message: 16/02/2005, 21h53

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