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 :

Question opérateur =


Sujet :

C++

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    197
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 197
    Points : 89
    Points
    89
    Par défaut Question opérateur =
    Bonjour,
    tous d'abord une première question pour L1=L1;
    avec L1 un objet quelconque .
    la syntaxe de l'opérateur serai donc : Object operator = ( Object L){... return *this}
    Afin de passer en paramètre une copie de L1 ,qui me permettra de supprimer L1 et de le recopier à partir de sa copie ?

    Deuxième question j'ai un bug dans l'exécution de mon code je ne comprend pas pourquoi.

    (les fonctions sont volontairement tronquées)
    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
     
    class Liste { ...
     
    Liste(){prems=NULL;last=NULL;}
     
    Liste(int k){   // constructeur spécial
    		prems = new Maillon2;
    		prems->valeur=2;
    		prems->suivant=NULL;
    		last=prems;		
    }
    Liste operator = (const Liste L1){ //mon operator = 
    		//free2();		
    		prems = new Maillon2;
    		prems->valeur=2;
    		prems->suivant=NULL;
    		last=prems;	
    		return *this;
    }
    void afficher(){
    		Maillon2 *temp=prems;
    		if(prems==NULL)
    			cout<< "Liste vide" << endl;
    		while(temp!=NULL){
    			temp->afficher();
    			temp=temp->suivant;
    		}
    }
    dans mon main je fait

    Liste L1(1),L2;
    L1.afficher();
    L2.afficher();

    cela fonctionne correctement mais si je fait .

    Liste L1(1),L2;
    L2=L1;
    L1.afficher();
    L2.afficher();

    A l'exécution j'ai une erreur type corruption de mémoire .Je ne comprend pas pk surtout que le code et le même pour l'opérateur = et mon constructeur spécial.

  2. #2
    Modérateur
    Avatar de bruno_pages
    Homme Profil pro
    ingénieur informaticien à la retraite
    Inscrit en
    Juin 2005
    Messages
    3 534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : ingénieur informaticien à la retraite
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juin 2005
    Messages : 3 534
    Points : 6 723
    Points
    6 723
    Par défaut
    Bonjour,

    première remarque : mettez le code entre des balises code (bouton #)

    second remarque :
    Citation Envoyé par carton99 Voir le message
    la syntaxe de l'opérateur serai donc : Object operator = ( Object L){... return *this}
    plutôt ...(const Object & L) ...

    Citation Envoyé par carton99 Voir le message
    Afin de passer en paramètre une copie de L1 ,qui me permettra de supprimer L1 et de le recopier à partir de sa copie ?
    quel intéret ?
    L1=L1 ne devrait rien faire car la première chose à tester dans l'opérateur est de tester la non égalité

    dans Liste(int k) à quoi sert k, 2 ne devrait-il pas être remplacé par k ?

    dans operator = L1 n'est pas utilisé, ce n'est dons pas une affectation, et il faudrait remplacé le commentaire par une vraie libération

    Liste accède directement aux attributs de Maillon2, et à donc droit de le faire

    il aurait été préférable de définir une liste générique via une classe template

    Deuxième question j'ai un bug dans l'exécution de mon code...
    tel qu'il est je ne pense pas qu'il puisse y avoir de corruption mémoire, peut être cela était le cas avec free2 non commenté

    là on ne le voit pas, mais avez-vous défini le copy contructor ?

    sinon la stl définie déjà les listes

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    197
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 197
    Points : 89
    Points
    89
    Par défaut
    Merci pour la réponse.
    Bon déjà j'avoue que c'est un peu tordu, mais c'est juste des petits exo que je me donne pour apprendre.


    Ici : Object operator = ( Object L){... return *this}
    Je n'utilise pas (const Object & L) car dans ce fait je renverrai l'objet lui même.
    Je test qqch de plus compliqué (je me préoccupe pas de const ,au pire j’aurai un message d’erreur au moment du free) par contre je n’envoi pas volontairement la référence car je veux bien une copie de l’objet en paramètre.
    Si j’ai bien compris comment sa marche quand j’appel l’objet operator = ( Object L){... return *this}
    Le programme va créer un double de L qu’il supprimera après le return.

    Pour le reste l’idée (un peu tordu mais qui devrai marcher) c’était de supprimer la liste dans toutes les situations et de la recréer à partir de la liste envoyé.
    Du coup si on fait L1=L1 sa marche car je n’envoi pas la référence.

    Pour le reste on oubli sinon sa compliquerai trop l'explication.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Salut, et bienvenue sur le forum

    De manière générale, dés que tu travailles avec des pointeurs, tu dois te poser la question de savoir si ta classe a sémantique de valeur ou sémantique d'entité.

    En effet, seules les classes ayant sémantique de valeur devraient être copiables et assignables.

    Ensuite, si ta classe a, effectivement sémantique de valeur et qu'elle manipule des pointeurs, il faut prendre quelques précautions:

    Pour éviter les problèmes, il faut que le constructeur par copie veille à allouer un espace mémoire propre à l'instance pour tous les pointeurs dont la classe a la responsabilité de la durée de vie.

    En effet, si tu as une classe responsable de la durée de vie d'un pointeur, comme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class MaClass
    {
        public:
            MaClass(int i):ptr(new int[i]), count(i)
            {
            }
            ~MaClass(){delete[] ptr;}
        private:
            int *ptr;
            int count;
    };
    il faut savoir que le constructeur par copie ajouté automatiquement par le compilateur va se contenter de copier les différents membres de la classe... membre à membre.

    Or, un pointeur, ce n'est jamais qu'une valeur numérique "classique" dont la particularité est... de contenir l'adresse à laquelle on trouve la variable pointée.

    Si tu te contente de copier un pointeur, tu auras donc deux instances de la classe dont le membre pointe... vers la même adresse mémoire

    Le résultat ne se fera pas attendre: lorsque la première variable est détruite, la mémoire allouée pour le pointeur sera libérée et, lorsque la deuxième variable sera détuire, il y aura une nouvelle tentative de libération de la mémoire.

    Or, les tentatives de double libération de la mémoire présentent... un comportement indéfini.

    Autrement dit, le comportement du destructeur lorsqu'il sera appelé sur la deuxième instance à être détruite pourrait parfaitement être... de lancer un missile atomique sur Cuba ou sur la place rouge

    C'est pourquoi, il faut que tu définisse toi-même le constructeur par copie de manière à t'assurer que deux instances différentes de ta classe ne partagent pas un même espace mémoire pour l'un de leur membre.

    La classe que je présentais plus haut devrait donc prendre la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class MaClass
    {
        public:
            MaClass(int i):ptr(new int[i]), count(i)
            {
            }
            MaClass(MaClass const & rhs):ptr(new int[rhs.i]),count(rhs.i){}
            ~MaClass(){delete[] ptr;}
        private:
            int *ptr;
            int count;
    };
    Mais cela n'aura résolu qu'une partie du problème, car l'opérateur d'affectation renvoie classiquement... ce qui est pointé par this...

    Or, this dispose... d'un pointeur, pour lequel de la mémoire a été allouée, et l'idée sera... de faire pointer ce pointeur vers la mémoire allouée pour le membre correspondant de... la copie de l'objet à assigner.

    Et, si on se contente de changer l'adresse vers laquelle pointe le membre, nous risquons de perdre... l'adresse vers laquelle il pointait avant l'assignation, et donc d'occasionner une fuite mémoire

    Aussi, le meilleur moyen de s'assurer que la mémoire anciennement allouée pour le pointeur membre de this soit correctement libérée est-il le recours à un idiome nommé "copy and swap".

    L'idée de base est, finalement "toute bête": la norme garanti que le destructeur d'un objet est automatiquement appelé lorsque l'on quitte la portée dans laquelle l'objet est déclaré.

    Si on crées une variable temporaire dans l'opérateur d'affectation, son destructeur sera donc appelé... quand on quittera l'opérateur, et, comme nous sommes maintenant en mesure de copier correctement notre classe, il suffit d'échanger le pointeur d'une copie temporaire et de l'objet courent

    Au final, si ta classe a sémantique de valeur et qu'elle manipule des pointeurs, il y aura quatre fonctions à définir, qui forment ce que l'on appelle "la forme canonique de coplien":
    1. le constructeur
    2. le constructeur par copie
    3. l'opérateur d'affectation
    4. le destructeur
    et la classe que j'ai utilisée comme exemple doit donc prendre la forme finale de
    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
    class MaClass
    {
        public:
            /* le constructeur */
            MaClass(int i):ptr(new int[i]), count(i)
            {
            }
            /* le constructeur par copie, qui s'assure que deux instance
             * ne partagent pas un même espace mémoire
             */
            MaClass(MaClass const & rhs):ptr(new int[rhs.i]),count(rhs.i){}
            /* l'opérateur d'affectation */
            MaClass & operator = (MaClass c) /*comme c est passé par valeur,
                                              * c sera une copie (qui n'existera
                                              * que durant l'exécution de la
                                              * fonction) de l'objet passé en 
                                              * paramètre
                                              */
            {
                /* on interverti le pointeur de c et le pointeur de l'objet 
                 * courent nous aurions pu envisager d'autres solutions 
                 * pour ce faire :D
                 */
                std::swap(ptr, c.ptr);
                /* Pour les autres membres, il n'y a pas de problèmes: une 
                 * assignation toute simple sera suffisante :D
                 */
                count=c.count;
                /* nous renvoyons l'objet courent */
                return *this;
            }/* c est détruit ici, et son destructeur appelé automatiquement :D */
            ~MaClass(){delete[] ptr;}
        private:
            int *ptr;
            int count;
    };

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    197
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 197
    Points : 89
    Points
    89
    Par défaut
    Oui effectivement j'avais oublier l'histoire de la copie de pointeur ,

    La forme de coplien était présente je n'avai ici recopié que la partie sensible.


    Merci pour ces explications.Je vai pouvoir passer à la suite .

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

Discussions similaires

  1. Question opérateur de différence
    Par aurelien13008 dans le forum Langage
    Réponses: 14
    Dernier message: 09/03/2011, 15h36
  2. Question opérateurs binaires
    Par Evocatii dans le forum Langages de programmation
    Réponses: 13
    Dernier message: 15/01/2009, 19h44
  3. [Tableaux] Petite question d'opérateurs
    Par Hurin dans le forum Langage
    Réponses: 2
    Dernier message: 01/08/2007, 17h28
  4. Réponses: 17
    Dernier message: 21/03/2007, 10h25
  5. question sur les opérateurs
    Par isidore dans le forum C++
    Réponses: 10
    Dernier message: 25/02/2005, 18h46

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