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 :

constructeur de copie OR operator= ?


Sujet :

C++

  1. #1
    Membre régulier Avatar de foolib
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    111
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Juillet 2008
    Messages : 111
    Points : 90
    Points
    90
    Par défaut constructeur de copie OR operator= ?
    Mon problème est simple, dans le code ci dessous, je ne comprends pas pourquoi à la ligne indiquée dans main, le constructeur de copie est appelé plutôt que la méthode 'operator=' de la classe ...
    1 - Le constructeur de copie est censé n'intervenir qu'en cas de d'initialisation d'un objet : alors pourquoi b est concidéré non initialisé ?
    ( il est déclaré à la ligne du dessus, donc un constructeur par defaut a déjà fait le boulo non ?)
    2 - Enfin, que faudrait il pour que la méthode operator= soit appelée à cet endroit plutôt que le constructeur de copie ?

    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
    #include <iostream>
    using namespace std;
     
    class point
    { int x, y;
    public :
    point (int abs=0,int ord=0){ 
    	x=abs; 
    	y=ord;
    }
    point (const point &p){ 
    	x=p.x; 
    	y=p.y;
    }
    ~point(){}
    point operator=(const point &p);
    point symetrique();
    }
     
    point point::symetrique(){
    	point res;
    	res.x = -x;	res.y = -y;
    	return res;
    }
     
    point operator=(const point &p){
    	x=p.x; 
    	y=p.y;
    	return *this;
    }
     
    int main(){
     
    point a(1,3), b;
     
    b = a.symetrique();  // <------ICI
     
    return 0;
    }
    Merci d'avance

  2. #2
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 617
    Points
    15 617
    Par défaut
    Bonjour RipCode

    La ligne suivante est une simple déclaration sans initialisation :
    Essaie de "forcer" l'initialisation avec pour appeler le constructeur par défaut :

  3. #3
    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
    Et remplacer un code correct par un code faux ? T'as de drole de conseils gbdivers.
    (pour plus d'information sur pourquoi "point b();" est faux, google -> "C++ most vexing parse", c'est une erreur vicieuse et très courante)

    Sinon, RipCode, sous vs2005, ton code passe bien dans l'opérateur= comme prévu. Tu utilises quel compilateur ?

  4. #4
    zul
    zul est déconnecté
    Membre éclairé Avatar de zul
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    498
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 498
    Points : 699
    Points
    699
    Par défaut
    Sans certitude, mais je pense que le compilateur peut (doit) optimiser dans ce cas précis, il n'a aucune raison de construire un objet par défaut, puisque le premier traitement que tu fais sur cette objet, c'est de lui affecter le retour de a.symetrique() (et dans ce cas là, il est valide d'appeler le constructeur par copie).

  5. #5
    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, il ne peut pas optimiser ici, car :
    force l'appel du constructeur par défaut.

    Le comilateur optimise dans ce cas là :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Point b = a.symetrique();
    L'optimisation étant qu'il n'y a plus de point temporaire crée dans la fonction symetrique() car le compilateur construit directement dans le point b. On a donc que deux appels aux constructeurs par défaut dans tous le programme, un pour a et un pour b, alors que dans le programme original de RipCode on a :
    Ctor (pour a)
    Ctor (pour b)
    Ctor (pour le temporaire dans symetrique)
    Operator = (pour la copie)

    Edit : D'ailleurs il y a une petite erreur dans l'operateur=, il faut renvoyer un point&, pas un point.

  6. #6
    r0d
    r0d est actuellement connecté
    Expert éminent

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 266
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

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

    chez moi (j'ai compilé et testé avec visual 2008 express ed.), il passe bien par l'opérateur =, même en release avec optimisations.
    Cela dit, il passe bien par l'opérateur par copie avant. C'est dans la fonction symetrique(), à la ligne:
    qu'il fait une copie du point*. Mais ensuite, il affecte bien b à ce que retourne symetrique() en utilisant l'opérateur =.


    * ce qui est normal. Pour éviter cela, il faut passer par une référence.

  7. #7
    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
    Ben non c'est pas normal, rod.
    Ce comportement là (un constructeur par copie à la ligne return res; puis une affectation avec l'opérateur =) est typique du mode debug sous VS.
    En release, la ligne b = a.symetrique() ne déclenche qu'un appel à l'opérateur = .

    (Mais le must reste Point b = a.symetrique(), comme dit plus haut, car il n'y a acune copie du tout)

  8. #8
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 617
    Points
    15 617
    Par défaut
    Merci Arzar
    C'est probablement une erreur que je dois faire régulièrement...

  9. #9
    r0d
    r0d est actuellement connecté
    Expert éminent

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 266
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 266
    Points : 6 688
    Points
    6 688
    Billets dans le blog
    2
    Par défaut
    Effectivement, Arzar a raison, je viens de vérifier
    Il faut que je révise mes classiques moi

  10. #10
    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 Arzar Voir le message
    Et remplacer un code correct par un code faux ? T'as de drole de conseils gbdivers.
    (pour plus d'information sur pourquoi "point b();" est faux, google -> "C++ most vexing parse", c'est une erreur vicieuse et très courante)
    Et renvoyer vers des recherches approximatives ? Tu as de drôle de conseil Arzar Alors qu'on a la réponse en français dans la F.A.Q. de développez.

  11. #11
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 382
    Points : 41 588
    Points
    41 588
    Par défaut
    Citation Envoyé par Arzar Voir le message
    Non, il ne peut pas optimiser ici, car :
    force l'appel du constructeur par défaut.
    Le code du constructeur par défaut est visible et trivial, le compilateur peut donc l'inliner, ce qui revient ici à le supprimer.

    PS: Pourquoi l'opérateur = de ce code retourne-t-il une copie?

  12. #12
    Membre régulier Avatar de foolib
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    111
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Juillet 2008
    Messages : 111
    Points : 90
    Points
    90
    Par défaut Debriefing
    Tout d'abord, merci à chacun d'avoir participé à ce post
    Je pense avoir ma réponse ... en fait les deux semblent appelés

    Voilà ce que j'ai quand je print

    MAIN ====== INIT
    - CTRCT-DEFAUT a ( Appel du constructeur par défaut)
    - CTRCT-DEFAUT b ( Appel du constructeur par défaut)
    MAIN ====== SYMETRIQUE
    - CTRCT-DEFAUT ( Appel du constructeur par défaut pour l'objet locale dans symetrique() )
    MAIN ====== Affectation b = a.symetrique();
    - END-SYM
    - OPERATOR= ( Appel de l' operator= )
    - COPY ( Appel du constructeur par recopie qui reçoit la valeur retournée par operator=)
    MAIN ====== END SYMETRIQUE

    L'opérateur = (parce qu'il retourne une valeur) donne le relais au constructeur de recopie

    Citation :"Lorsque la transmission d'un argument ou d'une valeur de retour se fait par valeur, elle met en œuvre une recopie.
    Lorsqu'elle concerne un objet, cette recopie est réalisée soit par le constructeur de recopie prévu par le développeur de la classe s'il l'a prévu, soit le cas échéant par le constructeur de recopie par défaut"


    ??

    Pour ceux qui veulent savoir pourquoi l'operator= renvoie par valeur :
    Mon operator= est tiré du livre de "Apprendre le C++" par C.Delannoy ; il donne une redéfinition générale de cet opérateur de la manière suivante
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    obj obj::operator= (const obj & o)
    {
    //instructions
    ...
     
    return * this;
    }
    De cette manière, une instruction telle que b=a aura une valeur ... on pourra du coup chaîner les affectations.
    Si toutefois on ne souhaite faire que des affections simple b=a, l' operator= peut (voir doit) n'avoir aucune valeur de retour (void).

    PS : IDE -> Code::Blocks

  13. #13
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 382
    Points : 41 588
    Points
    41 588
    Par défaut
    Citation Envoyé par RipCode Voir le message
    Pour ceux qui veulent savoir pourquoi l'operator= renvoie par valeur :
    Mon operator= est tiré du livre de "Apprendre le C++" par C.Delannoy ; il donne une redéfinition générale de cet opérateur de la manière suivante
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    obj obj::operator= (const obj & o)
    {
    //instructions
    ...
     
    return * this;
    }
    De cette manière, une instruction telle que b=a aura une valeur ... on pourra du coup chaîner les affectations.
    Si toutefois on ne souhaite faire que des affections simple b=a, l' operator= peut (voir doit) n'avoir aucune valeur de retour (void).
    Cela ne me donne aucune raison valable à mes yeux de renvoyer par valeur plutôt que par référence (comme c'est conseillé partout ailleurs).

  14. #14
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 282
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 282
    Points : 11 036
    Points
    11 036
    Par défaut
    Citation Envoyé par RipCode Voir le message
    Pour ceux qui veulent savoir pourquoi l'operator= renvoie par valeur :
    Mon operator= est tiré du livre de "Apprendre le C++" par C.Delannoy ;
    Ha!

  15. #15
    Membre régulier Avatar de foolib
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    111
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Juillet 2008
    Messages : 111
    Points : 90
    Points
    90
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Cela ne me donne aucune raison valable à mes yeux de renvoyer par valeur plutôt que par référence (comme c'est conseillé partout ailleurs).
    Honnêtement je ne vois pas non plus la raison valable ...
    Pourriez vous me dire si ce qui suit est la seule différence entre les deux méthodes (retour par valeur/reference)?

    la différence vient du fait que par valeur, les données sont copiées temporairement au moment du retour pour être traitées.
    Par référence, les données seront exploités depuis l'objet référencé sans objet temporaire (gain de mémoire).
    Merci

  16. #16
    screetch
    Invité(e)
    Par défaut
    hmm pas vraiment
    même si c'est un petit peu capillotracté
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    (a=b).setValue(2);
    ce coode effectue l'opérateur a = b donc b est copié dans a, puis on change une valeur dans a
    si l'opérateur = renvoie une référence, ca marche
    si l'opérateur = renvoie une copie, ca ne fait pas ce que l'on attend

    c'est une erreur de renvoyer une copie, une erreur d'autant plus grave qu'elle passe inapercu partout.

    je me demande si c'est valide de renvoyer rien du tout (void) pour éviter la confusion ci-dessus. c'est pas pour les fois dans sa vie ou ca peut etre utile...

Discussions similaires

  1. [résolu]les constructeurs de copie
    Par pouss dans le forum Langage
    Réponses: 9
    Dernier message: 28/06/2005, 11h57
  2. Réponses: 3
    Dernier message: 24/04/2005, 15h19
  3. [C++]Heritage et constructeur de copie
    Par matazz dans le forum C++
    Réponses: 2
    Dernier message: 25/03/2005, 13h31
  4. Constructeur de copie modifiant le paramètre ?
    Par Nicodemus dans le forum C++
    Réponses: 4
    Dernier message: 12/01/2005, 22h25
  5. Constructeur de copie et Template: Transtypage
    Par ikkyu_os dans le forum Langage
    Réponses: 9
    Dernier message: 26/12/2004, 23h29

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