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. #21
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 641
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 641
    Par défaut
    Citation Envoyé par hiura Voir le message
    Faut faire gaffe pour le premier, le compilo peut assigner directement main::t à foo:t suivant comment il travaille.
    C'est bien pour cela que j'ai donné les informations qui permettent de reproduire le comportement observé, et que j'ai pris toutes les précautions d'usage afin d'établir le fait que je ne me base ici que sur une observation, qui peut être dépendante de l'implémentation

    (je pourrais aussi avoir recours à la norme, mais j'avoue avoir la flemme aujourd'hui )
    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

  2. #22
    Membre émérite
    Inscrit en
    Juillet 2005
    Messages
    512
    Détails du profil
    Informations forums :
    Inscription : Juillet 2005
    Messages : 512
    Par défaut
    J'ai testé ton code avec codeblock gcc et j'obtiens le même résultat.
    Puis je l'ai testé avec BCB et là le résultat est différent :

    recuperons l'objet par valeur
    ctor
    copy ctor
    dtor
    et maintenant par reference constante
    ctor
    copy ctor
    dtor
    fin du test et destruction
    dtor
    dtor
    Ce résultat me semble plus coherant.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 641
    Par défaut
    Vérification faite, ce comportement est laissé à discrétion de l'implémentation
    Citation Envoyé par la norme chapitre 6.6.3 return statment
    A return statement without an expression can be used only in functions that do not return a value, that is, a
    function with the return type void, a constructor (12.1), or a destructor (12.4). A return statement with an expression of non-void type can be used only in functions returning a value; the value of the expression is returned to the caller of the function. The expression is implicitly converted to the return type of the function in which it appears. A return statement can involve the construction and copy of a temporary object (12.2). Flowing off the end of a function is equivalent to a return with no value; this results in undefined
    behavior in a value-returning function.
    (le point important étant l'usage de can et non de must)
    Citation Envoyé par la norme, chapitre 12.8 Copying class objects, §15
    When certain criteria are met, an implementation is allowed to omit the copy construction of a class object, even if the copy constructor and/or destructor for the object have side effects. In such cases, the implementation treats the source and target of the omitted copy operation as simply two different ways of referring to the same object, and the destruction of that object occurs at the later of the times when the two objects would have been destroyed without the optimization.111) This elision of copy operations is permitted in the following circumstances (which may be combined to eliminate multiple copies):
    in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object with the same cv-unqualified type as the function return type, the copy operation can be omitted by constructing the automatic object directly into the function’s return value
    <snip>
    En deux mots, personne n'a tout à fait tord... ni tout à fait raison

    Les deux comportements sont parfaitement admis
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 641
    Par défaut
    A la réflexion, je trouve même que le comportement qui permet d'éviter la copie de l'objet renvoyé est beaucoup plus logique dés qu'il s'agit de structures ou de classes:

    Pour un type primitif, on peut effectivement estimer que la copie ne pose pas trop de problème, ni en temps ni en utilisation de la mémoire, mais, pour une classe ou une structure:

    La copie peut être très couteuse en temps et en mémoire
    que faire avec une classe non copiable

    Cela veut-il dire que nous ne pourrions pas écrire un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    NonCopiable foo(/* parametres */)
    {
        /* tests de validités des paramètres */
        NonCopiable t(/* parametres*/);
        return t;
    }
    Ca promettrait du plaisir (car nous serions tenu de la créer dynamiquement ou de la renvoyer par référence... mais est-ce seulement opportun )
    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. #25
    Membre éprouvé
    Étudiant
    Inscrit en
    Octobre 2007
    Messages
    189
    Détails du profil
    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2007
    Messages : 189
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Cela veut-il dire que nous ne pourrions pas écrire un code proche de
    Oui. J'ai fait quelque tests avec MinGW ( basé sur gcc 3.4 ) :
    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
    40
    41
    42
    43
    class NC {
        NC(const NC&);
        NC& operator=(const NC&);
    public :
        NC() { }
    };
     
    NC a(void) {
        return NC(); // error: `NC::NC(const NC&)' is private
    }
     
    NC& b(void) {
        return NC(); // error: invalid initialization of non-const reference of type 'NC&' from a temporary of type 'NC'
    }
     
    const NC& c(void) {
        return NC(); // error: `NC::NC(const NC&)' is private
        // warning: returning reference to temporary
    }
     
    const NC d(void) {
        return NC(); // error: `NC::NC(const NC&)' is private
    }
     
    NC e(void) {
        NC t;
        return t; // error: `NC::NC(const NC&)' is private
    }
     
    NC& f(void) {
        NC t; // warning: reference to local variable `t' returned
        return t;
    }
     
    const NC& g(void) {
        NC t; // warning: reference to local variable `t' returned
        return t;
    }
     
    const NC h(void) {
        NC t;
        return t; // error: `NC::NC(const NC&)' is private
    }
    Seul f et g fonctionne. Mais je me suis pas encore intéressé à " ces variables retournées peuvent-elles être utilisées ? "

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

    Informations forums :
    Inscription : Octobre 2007
    Messages : 189
    Par défaut
    J'ai été un peu plus loin :
    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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    class NCs {
        NCs(const NCs&);
        NCs& operator=(const NCs&);
    public :
        NCs(int i) : _i(i) { }
        int _i;
    };
     
    NCs& fs(void) {
        NCs t(42); // warning: reference to local variable `t' returned
        return t;
    }
     
    const NCs& gs(void) {
        NCs t(42); // warning: reference to local variable `t' returned
        return t;
    }
     
    int main()
    {
        std::cout << "Hello world!" << std::endl;
     
        NCs x1 = fs(); // error: `NCs::NCs(const NCs&)' is private
        NCs x2 = gs(); // error: `NCs::NCs(const NCs&)' is private
     
        NCs& x3 = fs();
        NCs& x4 = gs(); // error: invalid initialization of reference of type 'NCs&' from expression of type 'const NCs'
     
        const NCs& x5 = fs();
        const NCs& x6 = gs();
     
     
        std::cout << x3._i << '\n' << x5._i << '\n' << x6._i << std::endl;
        /*
            Sortie :
    2293472
    2293472
    2293472
            Par contre, si dans fs et/ou gs on place un std::cout la sortie est bien :
    42
    42
    42
            A ajouter ( par exemple ) :
    std::cout << "";
        */
     
        const NCs x7 = fs(); // error: `NCs::NCs(const NCs&)' is private
        const NCs x8 = gs(); // error: `NCs::NCs(const NCs&)' is private
     
        return 0;
    }
    Mais je viens de réaliser que le comportement change assez brutalement rien qu'en changeant les options d'optimisations ! Ci-dessus c'est les remarques avec -O2, mais si je mets -O3 je n'ai aucun problème.

  7. #27
    Membre expérimenté
    Profil pro
    Inscrit en
    Août 2007
    Messages
    190
    Détails du profil
    Informations personnelles :
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations forums :
    Inscription : Août 2007
    Messages : 190
    Par défaut
    Citation Envoyé par koala01 Voir le message
    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()
    Sans NRVO on devrait plutôt obtenir quelque chose comme ça :
    recuperons l'objet par valeur
    ctor
    copy ctor
    dtor
    copy ctor
    dtor
    et maintenant par reference constante
    ctor
    copy ctor
    dtor
    fin du test et destruction
    dtor
    dtor

  8. #28
    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
    Par défaut
    En C++03, la conversion d'une rvalue en lvalue requiert la possibilité de copier le type.

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 2 PremièrePremière 12

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