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 :

Construire un objet avec l'opérateur d'assignation


Sujet :

C++

  1. #1
    Invité
    Invité(e)
    Par défaut Construire un objet avec l'opérateur d'assignation
    Bonjour,

    Jusqu'à maintenant voilà comment je procédais pour instancié mes objets :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    // sur la pile, statique
    MyObject instanceA;
    MyObject instanceB(42, "cpp_qt_lover");
     
    // sur le tas, dynamique
    MyObject* instanceA = new MyObject();
    MyObject* instanceB = new MyObject(42, "cpp_qt_lover");
    Voilà, comme j'étais un peu fatigué et que je voulais ne plus utilisé d'allocation dynamique, j'ai transformé le code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    MyObject* instanceA = new MyObject();// original
    MyObject instanceA = MyObject();// retiré le new et l'opérateur*
    Et surprise, là ou je m'attendais à une erreur du compilateur, et bien tout fonctionnait... Je voulais savoir si c'était une autre façon de faire ou si sa signifiait autre chose... Merci d'avance pour vos réponses.

  2. #2
    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 Abdelite Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    MyObject* instanceA = new MyObject();// original
    MyObject instanceA = MyObject();// retiré le new et l'opérateur*
    Et surprise, là ou je m'attendais à une erreur du compilateur, et bien tout fonctionnait... Je voulais savoir si c'était une autre façon de faire ou si sa signifiait autre chose... Merci d'avance pour vos réponses.
    Non non, il n'y a aucuns problèmes... du moment que tu as un constructeur de copie: cela revient alors à faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    MyObject* temp = new MyObject();
    MyObject instanceA(temp);
    delete temp;
    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++.

  3. #3
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Bonjour,

    ce que je ne comprends pas, c'est que ce code ne devrait pas compiler normalement. Il est interdit, en c++, de déclarer deux variables du même nom mais de types différents dans le même scope.
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  4. #4
    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,

    outre le fait que le compilateur te jetterait normalement du fait de la re déclaration d'une variable, il n'y a strictement aucune raison pour que cela ne fonctionne pas...

    Si tu ne prend pas la précaution de les désactiver explicitement (soit en les déclarant sans les définir dans l'accessibilité privée, soit (merci la nouvelle norme) en les spécifiant delete), toute classe/structure dispose systématiquement d'un constructeur par copie et d'un opérateur d'affectation (en plus du destructeur et du constructeur par défaut si tu ne déclare pas de constructeur perso): cela fait partie des fameux Big Four .

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MonType var = MonType(); //affectation explicite
    est donc presque similaire à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MonType var // appel implicite du constructeur par défaut
    et, NRVO aidant, il y a même de fortes chances pour que le binaire soit strictement identique
    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 expert Avatar de jabbounet
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juin 2009
    Messages
    1 909
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Juin 2009
    Messages : 1 909
    Points : 3 284
    Points
    3 284
    Par défaut
    Citation Envoyé par r0d Voir le message
    Bonjour,

    ce que je ne comprends pas, c'est que ce code ne devrait pas compiler normalement. Il est interdit, en c++, de déclarer deux variables du même nom mais de types différents dans le même scope.
    probable que ce soit un copier/coller mal placé
    bazar: http://www.improetcompagnie.com/publ...ctacles-6.html

    BÉPO la disposition de clavier francophone, ergonomique et libre: http://bepo.fr/wiki/Accueil

    Emacs Wiki: http://www.emacswiki.org/

    En attente de ce que produira: http://www.pushmid.com

  6. #6
    Invité
    Invité(e)
    Par défaut
    Merci pour vos réponses. Désolé pour le code présenté, quelques copier/coller qui ont mal tourné... Je remets le code ci-dessous :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    // sur la pile, statique
    MyObject instanceA;
    MyObject instanceB(42, "cpp_qt_lover");
     
    // sur le tas, dynamique
    MyObject* instanceC = new MyObject();
    MyObject* instanceD = new MyObject(42, "cpp_qt_lover");
    et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    MyObject* instanceC = new MyObject();// avant de modifier
    MyObject instanceC = MyObject();// retiré le new et l'opérateur*
    Il s'agit bien de 4 instances différentes...

    méphistopheles> Merci, donc c'est bien dans l'exemple que j'avais présenté le constructeur de copie qui est appelé.

    koala01> Pour ce code d'exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    MonType var = MonType();//affectation explicite
    Tu parles d'affectation, mais dans le cas ou var n'est pas déjà déclaré, est-ce que cette ligne qui déclare var est valide ? Je viens de tester, ça fonctionne.

  7. #7
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Oui cette ligne est valide.
    En fait, cette ligne fait deux chose distinctes en même temps: une déclaration et une affectation (ou initialisation). Et c'est parfaitement valide en C++, et même conseillé en fait.

    Mais il est tout de même plus propre de faire ainsi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MonType var(/* paramètres éventuels */);
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  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
    Tu parles d'affectation, mais dans le cas ou var n'est pas déjà déclaré, est-ce que cette ligne qui déclare var est valide ? Je viens de tester, ça fonctionne.
    En fait ce genre de code :

    T t = T();


    n'appelle pas l'op= mais le constructeur par recopie. .
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  9. #9
    Invité
    Invité(e)
    Par défaut
    Merci pour vos réponses ! Sujet

  10. #10
    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 C'est dans l'accessibilité privée que l'on déclare le constructeur par copie et l'opérateur d'affectation...
    Citation Envoyé par Goten Voir le message
    En fait ce genre de code :

    T t = T();


    n'appelle pas l'op= mais le constructeur par recopie. .
    Et encore... si (N)RVO ( (Named) Return Value Optimisation) ne passe pas par là

    Avec le phénomène (N)RVO qui est quand même implémenté par pas mal de compilateur, il se peut que le seul constructeur par défaut soit appelé

    @Abdelite>> Ce qu'il faut comprendre, c'est que, tant que tu ne lui donne pas de raison d'agir autrement, le compilateur va systématiquement implémenter la forme canonique de Coplien pour toutes les classes / structures qu'il rencontre.

    C'est à dire qu'il implémentera de manière implicite (sans que tu ne fasse quoi que ce soit) quatre fonctions particulières:
    1. le constructeur par défaut (ne prenant pas d'argument)
    2. le constructeur par copie
    3. le destructeur
    4. l'opérateur d'affectation

    Il n'y a donc, a priori, aucune raison pour qu'il rechigne à copier ou à affecter une instance d'une classe à une variable dont le type est compatible

    Pour que le compilateur renonce à fournir l'implémentation d'une de ces fonctions, il "suffit" de la déclarer, ou, pour le constructeur par défaut, de déclarer n'importe quel constructeur qui ne soit pas constructeur par copie.

    Le compilateur fournira alors le code binaire de la fonction en question sur base... de l'implémentation que tu en auras (éventuellement) donnée.

    C'est la raison pour laquelle, lorsque l'on crée une classe non copiable et / ou non assignable, on se contente de déclarer le constructeur par copie et / ou l'opérateur d'affectation dans l'accessibilité privée sans les implémenter.

    Dans la majorité des cas (comprend: tant que l'on est dans une situation dans laquelle on n'a pas accès à la partie private de la classe) cette simple manoeuvre permet d'obtenir une erreur proche de "le constructeur par copie (ou l'opérateur d'affectation) est private dans ce contexte"

    Une minorité de cas peut cependant avoir accès à cette déclaration private du constructeur par copie / de l'opérateur d'affectation: Lorsque l'on se trouve dans une fonction membre de la classe ou dans une fonction pour laquelle l'amitié avec la classe s'applique.

    L'erreur sera alors reportée à l'étape d'édition de liens, l'éditeur de liens se plaignant d'un "symbole indéfini", car le symbole du constructeur par copie / de l'opérateur d'affectation existant, mais l'éditeur de liens ne trouve aucun code binaire correspondant.

    La nouvelle norme ajoute la possibilité de dire de manière explicite que l'une de ces fonctions n'existe pas (NB: une classe que l'on ne pourrait pas construire ou que l'on ne pourrait pas détruire n'a strictement aucun intérêt, hein cette possibilité n'a donc d'intérêt que pour le constructeur par copie ou l'opérateur d'affectation ) en ajoutant = delete après la déclaration:
    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
    class NonCopiable
    {
        public:
            NonCopiable(); // constructeur par défaut
            NonCopiable(NonCopiable const &) = delete; // uniquement en C++1x
            NonCopiable & operator = (NonCopiable const &) = delete; //uniquement en C++1x
            /* si on ne déclare pas le destructeur, le compilateur l'ajoute 
             * automatiquement et le rend public et non virtuel
             */
        private:
             /* rendent la classe non copiable  / non affectable
              * !!! pour que ce soit effectivement le cas, on ne fournit pas
              * d'implémentation pour ce qui suit :D
              */
            NonCopiable(NonCopiable const &); /* valide depuis toujours */
            NonCopiable & operator= (NonCopiable const &); /* idem */
     
    };
    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

  11. #11
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    A noter que même si le (N)RVO s'applique il faut quand même que le constructeur par copie soit au moins déclaré et accessible pour que la compilation soit valide.

  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 Flob90 Voir le message
    A noter que même si le (N)RVO s'applique il faut quand même que le constructeur par copie soit au moins déclaré et accessible pour que la compilation soit valide.
    Oui, bien sur, autrement, on entre dans la situation d'une classe non copiable

    La réelle différence avec / sans (N)RVO se verra au niveau du binaire généré
    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
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Bonjour,
    Citation Envoyé par Abdelite Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    MyObject* instanceC = new MyObject();// avant de modifier
    MyObject instanceC = MyObject();// retiré le new et l'opérateur*
    Ceci dit, ces 2 lignes de codes sont différentes puisque tu as la gestion de la libération de la première à faire explicitement (delete) alors que la seconde est libérée dès que la variable sort de sa portée (implémentation tas vs pile). Il n'est donc pas anodin d'enlever * et new, ce n'est pas la même chose.

  14. #14
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Ceci dit, ces 2 lignes de codes sont différentes puisque tu as la gestion de la libération de la première à faire explicitement (delete) alors que la seconde est libérée dès que la variable sort de sa portée (implémentation tas vs pile). Il n'est donc pas anodin d'enlever * et new, ce n'est pas la même chose.
    Rassure toi j'en avais conscience.

    koala01> Goten> Donc si mon constructeur de copie étais privé, le chose suivante aurais été impossible ? T t = T();

  15. #15
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par Abdelite Voir le message
    Rassure toi j'en avais conscience.
    C'est bien ce que je pensais, mais la lecture du fil ne m'a pas paru évidente sur ce point, c'est pour ça que j'ai préféré préciser.
    Citation Envoyé par Abdelite Voir le message
    koala01> Goten> Donc si mon constructeur de copie étais privé, le chose suivante aurais été impossible ? T t = T();
    Oui. Tu aurais eu une erreur disant que le constructeur de copie est privé (et idem si protégé bien sur).
    De la même façon, si tu utilises =delete de C++0x sur le constructeur de copie, tu aurais une erreur indiquant que le constructeur de copie est non défini.

  16. #16
    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 Flob90 Voir le message
    A noter que même si le (N)RVO s'applique il faut quand même que le constructeur par copie soit au moins déclaré et accessible pour que la compilation soit valide.
    Oui c'est pour ça que j'ai pas mentionné le NRVO d'ailleurs... (pas besoin de l'encombrer avec ce genre de notion)
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  17. #17
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Petite note: je ne vois pas de (N)RVO applicable ici ((Named) Return Value Optimization). Ce qui est applicable est la permission plus générale de l'élision du constructeur de copie appliqué aux temporaires.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  18. #18
    Invité
    Invité(e)
    Par défaut
    Quelqu'un ici pourrait m'expliquer ce qu'est NRVO/(N)RVO ? Merci.

  19. #19
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311

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

Discussions similaires

  1. Réponses: 10
    Dernier message: 22/09/2008, 10h23
  2. [Struts] pb avec l'opérateur '/'
    Par njac dans le forum Struts 1
    Réponses: 6
    Dernier message: 29/06/2004, 12h19
  3. [Float] pb avec l'opérateur '/'
    Par njac dans le forum Langage
    Réponses: 4
    Dernier message: 29/06/2004, 12h10
  4. construire 1 gateway avec 1 carte réseaux sous débian
    Par regular dans le forum Développement
    Réponses: 4
    Dernier message: 28/08/2003, 01h05
  5. A propos des modèles d'objet (avec sources)
    Par DevX dans le forum C++Builder
    Réponses: 14
    Dernier message: 01/12/2002, 12h22

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