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 :

[bug] Initialisation invalide d'une référence non const à partir d'un temporaire.


Sujet :

C++

  1. #1
    Membre éprouvé
    Avatar de méphistopheles
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    1 551
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 1 551
    Points : 1 220
    Points
    1 220
    Par défaut [bug] Initialisation invalide d'une référence non const à partir d'un temporaire.
    bonjour.

    J'ai défini une petite classe comme suit:


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class solid_pos: public point
    {
        angle<SOLID_ANGLE_PREC> dir;
     
        public:
        solid_pos(const point & pt=point(),angle<SOLID_ANGLE_PREC> agl=angle<SOLID_ANGLE_PREC>());
        solid_pos(const solid_pos & pos);
        inline solid_pos & operator-()const;
     
    };
    or dans l'implémentation de operator -:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    inline solid_pos & solid_pos::operator-()const
    {
        return solid_pos(point::operator-(),-dir); //plante ici
    }
    il me fait l'erreur suivante sur le return:
    ...solid_pos.h|28|erreur: invalid initialization of non-const reference of type ‘solid_pos&’ from a temporary of type ‘solid_pos’|
    ce que j'ai du mal à comprendre vu qu'une référence doit forcément s'initialiser à partir d'un objet...

    bref, un éclairement serait bienvenu.


    merci.
    Méphistophélès
    Si la solution ne résout pas votre problème, changez le problème...
    Cours et tutoriels C++ - FAQ C++ - Forum C++.

  2. #2
    Membre actif
    Étudiant
    Inscrit en
    Octobre 2007
    Messages
    189
    Détails du profil
    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2007
    Messages : 189
    Points : 213
    Points
    213
    Par défaut
    Tu ne peux pas retourner une référence sur un objet qui n'existe plus.

    Par contre, tu peux retourner une référence sur un objet constant, car le C++ s'arrange pour ne pas le supprimer tant <wrong>qu'il y a une référence dessus.</wrong> que la référence constante est en vie.

  3. #3
    Membre éprouvé
    Avatar de méphistopheles
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    1 551
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 1 551
    Points : 1 220
    Points
    1 220
    Par défaut
    Citation Envoyé par hiura Voir le message
    Tu ne peux pas retourner une référence sur un objet qui n'existe plus.

    Par contre, tu peux retourner une référence sur un objet constant, car le C++ s'arrange pour ne pas le supprimer tant qu'il y a une référence dessus.
    heu, qu'apelle-tu exactement un objet constant ? un objet revoyé avec une fonction const ? si oui, c'est déjà le cas...
    Méphistophélès
    Si la solution ne résout pas votre problème, changez le problème...
    Cours et tutoriels C++ - FAQ C++ - Forum C++.

  4. #4
    Membre confirmé
    Inscrit en
    Juillet 2005
    Messages
    512
    Détails du profil
    Informations forums :
    Inscription : Juillet 2005
    Messages : 512
    Points : 641
    Points
    641
    Par défaut
    Citation Envoyé par hiura
    car le C++ s'arrange pour ne pas le supprimer tant qu'il y a une référence dessus.
    Le C++ Aurait-il un ramasse miettes ?

  5. #5
    Membre actif
    Étudiant
    Inscrit en
    Octobre 2007
    Messages
    189
    Détails du profil
    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2007
    Messages : 189
    Points : 213
    Points
    213
    Par défaut
    Citation Envoyé par méphistopheles Voir le message
    heu, qu'apelle-tu exactement un objet constant ? un objet revoyé avec une fonction const ? si oui, c'est déjà le cas...
    Non, mais par une fonction qui retourne un objet const :
    Citation Envoyé par Lucien63 Voir le message
    Le C++ Aurait-il un ramasse miettes ?
    J'avais lu le principe du ramasse miettes y a vraiment longtemps, mais d'après ce que je me souviens il ne s'agit pas de ça.
    Soit le code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    T f(void);
    void g(void) {
      const T& = f();
    } // T est détruit, l'objet auquel il fait référence aussi.
    Le C++ va, dans ce cas particulier, garder en mémoire l'objet const retourné par f en mémoire et le détruire que quand la référence sera détruite.

    Lire http://herbsutter.wordpress.com/2008...portant-const/

    EDIT : ce code est faux, voir mon prochain message ( bien plus bas ) .

  6. #6
    Membre confirmé
    Inscrit en
    Juillet 2005
    Messages
    512
    Détails du profil
    Informations forums :
    Inscription : Juillet 2005
    Messages : 512
    Points : 641
    Points
    641
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    T f(void);
    
    void g(void) {
      const T& = f(); // ou est le type et ou est le nom de la variable ?
    } // T est détruit, l'objet auquel il fait référence aussi.
    T est un type ou une variable ?

    T est détruit, l'objet auquel il fait référence aussi
    Par quel artifice l'objet est-il détruit ?

  7. #7
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    T est un type.
    La portée.
    Boost ftw

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

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    Citation Envoyé par Lucien63 Voir le message
    Le C++ Aurait-il un ramasse miettes ?

    Pas du tout..
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  9. #9
    Membre confirmé
    Inscrit en
    Juillet 2005
    Messages
    512
    Détails du profil
    Informations forums :
    Inscription : Juillet 2005
    Messages : 512
    Points : 641
    Points
    641
    Par défaut
    Citation Envoyé par Goten
    Citation Envoyé par Lucien63
    Le C++ Aurait-il un ramasse miettes ?
    Pas du tout.
    Ça je savais, mais je disais cela en rapport à la reponse de hiura.
    Car je n'ai jamais vu que la destruction de toutes les références sur un objet fesait que c++ détruisait l'objet auquel elle fesaient références.

    Citation Envoyé par loufoque
    Citation Envoyé par Lucien63
    T est un type ou une variable ?
    T est un type.
    Je m'en doutais, mais je ne savait pas "que l'on pouvait détruire un Type" :
    Citation Envoyé par hiura
    // T est détruit,
    C'est pour cela que je posait la question !

    La portée
    Idem que plus haut. La variable référence est détruite ok, mais comment peut tu dire que l'objet auquel elle fait référence est détruit ?

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

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    T'a lu le gotw qu'a donné de hiura?

    tout est expliqué :
    However, C++ deliberately specifies that binding a temporary object to a reference to const on the stack lengthens the lifetime of the temporary to the lifetime of the reference itself
    C'est une feature du C++..
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  11. #11
    Membre confirmé
    Inscrit en
    Juillet 2005
    Messages
    512
    Détails du profil
    Informations forums :
    Inscription : Juillet 2005
    Messages : 512
    Points : 641
    Points
    641
    Par défaut
    J'ai été un peu vite,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    T f(void);
    void g(void) {
      const T& = f();
    } // T est détruit, l'objet auquel il fait référence aussi.
    Dans ce contexe là oui car l'objet retourné par f est une copie.

    Ce qui m'a induit en erreur c'est le premier prototype de la fonction
    Non, mais par une fonction qui retourne un objet const :
    Dans ce cas c'est tout a fait different.

  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
    Salut,

    La règle est simple: tout objet est détruit lorsque l'on quitte la portée dans laquelle il a été déclaré, exception fait du cas où il est renvoyé par valeur (c'est à dire, pas par référence ni référence constante).

    La portée dans laquelle un objet est déclaré est définie par la paire d'accolade où se trouve la déclaration de l'objet, c'est à dire n'importe quel bloc d'instruction faisant partie de l'implémentation d'une fonction.

    Pour les membres de classes et de structures, ils sont détruit au moment où l'objet du type de la classe ou de la structure est détruite (au moment où l'on quitte la portée dans laquelle l'objet du type de la structure ou de la classe est déclaré).

    C'est à dire que, parmis les trois fonctions suivantes, seule la première est autorisée
    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
    Type foo(/* parametres */ )
    {
        return Type(/* parametres */);
    }
    Type& badFoo(/* parametres */ )
    {
       return Type(/* parametres */); /* KO: renvoie une référence sur un objet
                                        * qui est détruit lorsque l'on passe
                                        * l'accolade fermante
                                        */
    }
    Type const& badFoo2(/* parametres */ )
    {
       return Type(/* parametres */); /* KO: renvoie une référence constante
                                        * sur un objet qui est détruit 
                                        * lorsque l'on passe l'accolade fermante
                                        */
    }
    Par contre, le code suivant serait accepté, car l'objet renvoyé est un membre (d'un membre) de la classe:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class MaClass
    {
        public:
            Type& createType(/* parametres */)
            {
                tab.push_back(Type(/*parametres*/));
                return *(tab.rbegin());
            }
        private:
            std::vector<Type> tab;
    };
    voire, le code suivant, s'il est opportun de l'envisager:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class MaClass
    {
        public:
            Type& createType(/* parametres */)
            {
                elem= new Type(/* parametres */);
                return *elem;
            }
        private:
            Type* elem;
    };
    Dans le cadre de l'opérateur "-", tu renvoie un objet qui n'est pas ton objet d'origine, tu dois donc le renvoyer par valeur, et non par référence:
    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
    class solid_pos: public point
    {
        angle<SOLID_ANGLE_PREC> dir;
     
        public:
        solid_pos(const point & pt=point(),
                  angle<SOLID_ANGLE_PREC> agl=angle<SOLID_ANGLE_PREC>());
        solid_pos(const solid_pos & pos);
        inline solid_pos  operator-()const;
     
    };
    inline solid_pos  solid_pos::operator-()const
    {
        return solid_pos(point::operator-(),-dir); //plante ici
    }
    par contre, pour l'opérateur -=, s'il est opportun de les définir, tu renverra en réalité ton objet d'origine modifié, et tu peux donc le renvoyer par référence
    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
    class solid_pos: public point
    {
        angle<SOLID_ANGLE_PREC> dir;
     
        public:
        solid_pos(const point & pt=point(),
                  angle<SOLID_ANGLE_PREC> agl=angle<SOLID_ANGLE_PREC>());
        solid_pos(const solid_pos & pos);
        inline solid_pos  operator-=()const;
     
    };
    inline solid_pos & solid_pos::operator-=(solid_pos const & rhs)
    {
        /* la logique pour appliquer l'opérateur */
        return *this
    }
    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 éprouvé
    Avatar de méphistopheles
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    1 551
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 1 551
    Points : 1 220
    Points
    1 220
    Par défaut
    merci beaucoup, je ne sait pas ce que j'avais quand j'ai codé ça, mais je n'était pas tres en forme.

    en me levant ce matin, le problème m'a paru évident.


    merci encore.
    Méphistophélès
    Si la solution ne résout pas votre problème, changez le problème...
    Cours et tutoriels C++ - FAQ C++ - Forum C++.

  14. #14
    Membre actif
    Étudiant
    Inscrit en
    Octobre 2007
    Messages
    189
    Détails du profil
    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2007
    Messages : 189
    Points : 213
    Points
    213
    Par défaut
    Oulà ! Je devais vraiment être fatigué quand j'ai écrit le code avant ! Il manque effectivement qqch :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    T f(void);
    void g(void) {
      const T& var = f(); // <- oubli du nom de la variable, ne compilait pas.
    } // var est détruit, l'objet auquel il fait référence aussi.
    Mea-culpa.

  15. #15
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Salut,
    La règle est simple: tout objet est détruit lorsque l'on quitte la portée dans laquelle il a été déclaré, exception fait du cas où il est renvoyé par valeur (c'est à dire, pas par référence ni référence constante).
    Pinaillons.
    La règle est même encore plus simple :
    Tout objet est détruit lorsque l'on quitte la portée dans laquelle il a été déclaré, sans aucune exception.

    Dans le cas d'un retour par valeur, c'est une copie temporaire qui est renvoyée.

  16. #16
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Tout objet est détruit lorsque l'on quitte la portée dans laquelle il a été déclaré, sans aucune exception.
    Ben justement, si, il y a une exception, le cas de l'affectation d'une référence const à cet objet, qui étend sa portée .

  17. #17
    Membre actif
    Étudiant
    Inscrit en
    Octobre 2007
    Messages
    189
    Détails du profil
    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2007
    Messages : 189
    Points : 213
    Points
    213
    Par défaut
    car la référence n'est pas un objet, mais un lien vers l'objet

  18. #18
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Non, l'objet local à la fonction est bien détruit en sortant de la portée.
    Par contre c'est vrai que la copie temporaire qui devait être détruite à la fin de l'instruction ("au point virgule") voit sa vie prolongée dans le cas d'une liaison à une référence constante....

    Bon ok, j'amende.

    "Tout objet est détruit lorsque l'on quitte la portée dans laquelle il a été déclaré, sauf les objets temporaires (rvalue) liés à des références constantes. Dans ce cas la durée de vie du temporaire s'étend à celle de la référence."

    Là ça devrait être bon non ?

  19. #19
    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
    Et pourtant:
    avec le code (basique je l'admet)
    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
    class Test
    {
        public:
            Test(){cout<<"ctor"<<endl;}
            Test(Test const&){cout<<"copy ctor"<<endl;}
            Test& operator=(Test const&)
            {
                cout<<"assignment"<<endl;
                return *this;
            }
            ~Test(){cout<<"dtor"<<endl;}
    };
    Test foo()
    {
        Test t;
        return t;
    }
     
    int main()
    {
        cout<<"recuperons l'objet par valeur"<<endl;
        Test t=foo();
        cout<<"et maintenant par reference constante"<<endl;
        Test const & r=foo();
        cout<<"fin du test et destruction"<<endl;
        return 0;
    }
    j'obtiens comme seul affichage:
    Code x : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    recuperons l'objet par valeur
    ctor
    et maintenant par reference constante
    ctor
    fin du test et destruction
    dtor 
    dtor
    (Gcc 4.4.0, Code::blocks, win XP SP3, sans gestion NRVO)

    Ce qui semble confirmer que l'objet n'est ni détruit, ni copié dans foo()
    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

  20. #20
    Membre actif
    Étudiant
    Inscrit en
    Octobre 2007
    Messages
    189
    Détails du profil
    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2007
    Messages : 189
    Points : 213
    Points
    213
    Par défaut
    Faut faire gaffe pour le premier, le compilo peut assigner directement main::t à foo:t suivant comment il travaille.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Réponses: 4
    Dernier message: 16/03/2010, 14h34
  2. Réponses: 12
    Dernier message: 23/05/2007, 21h40
  3. Piloter une application non office à partir d'access
    Par Marmotine dans le forum Access
    Réponses: 2
    Dernier message: 23/03/2006, 01h08
  4. Initialiser une référence membre d'une classe
    Par NicolasJolet dans le forum C++
    Réponses: 2
    Dernier message: 18/03/2006, 12h14
  5. Réponses: 10
    Dernier message: 24/09/2005, 19h19

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