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 (ou autre problème)


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Juin 2008
    Messages
    56
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 56
    Par défaut Constructeur de copie (ou autre problème)
    Salut.
    Me revoilà... encore...

    Dans ma super class ebovar, j'essaye surcharger l'opérateur << afin de retourner la concaténation de 2 chaines

    Je rappelle à quoi ressemble ma class (qui est sensé représenter un variant).
    Pour les chaîne j'utilise un pointer de string.
    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
    52
    53
    54
    class ebovar
    {
    public:
    	int var_type;
    	union {
    		int i;
    		float f;
    		bool b;
    		string *s;
    		map<ebovar, ebovar> *m;
    		void *o;
    	};
     
    // var is null
    	ebovar() {
    		i =0;
    		var_type = EBO_NULL;
    	}
    	~ebovar()
    	{
    		if (var_type == EBO_STRING)
    		{
    			printf("-- delete string %s\n", s->c_str());
    			delete s;
    			var_type = EBO_NULL;
    		}
    		else
    			printf("-- delete ebovar %s %d\n", this->getType().c_str(), i);
    	}
     
    	ebovar(const ebovar &source)
    	{
    		printf("++++ create copy of ebovar\n");
    	}
     
    // ...
    // ...
    // ...
     
    	ebovar(const char *data) {
    		s = new string(data);
    		printf("++ create string %s\n", s->c_str());
    		var_type = EBO_STRING;
    	}
    	ebovar(string data) {
    		s = new string(data);
    		printf("++ create string from ebovar %s\n", s->c_str());
    		var_type = EBO_STRING;
    	}
     
    // ...
    // ...
    // ...
    }
    Et ma surcharge est la suivante
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    ebovar operator<<(const ebovar &left_op, const ebovar &right_op)
    {
    	return ebovar(*(left_op.s) + *(right_op.s));
    }
    Tout marche sauf dans 1 cas, celui ou la destination est une des source de l'operation
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // Ce code fonctionne
    	ebovar _s1 = "Hello ";
    	ebovar _s2 = "World !";
    	ebovar _s3 = _s1 << _s2;
    	echo (_s3);
     
    // Ce code ne fonctionne pas
    	ebovar _s1 = "Hello ";
    	ebovar _s2 = "World !";
    	_s1 = _s1 << _s2;
    	echo (_s1);
    Le deuxième code génère l'erreur suivante
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    ++ create string Hello 
    ++ create string World !
    ++ create string from ebovar Hello World !
    -- delete string Hello World !
    Segmentation fault
    C'est comme si le problème venait du = qui n'arrive pas a transférer un object ebovar vers un autre déjà existant...
    j'ai cru que le problème venait du fameux constructeur de copie que je n'avais pas fait, mais il ne semble pas être appelé dans ce cas
    Faut-il surcharger le = ?

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 147
    Billets dans le blog
    4
    Par défaut
    Salut,

    oui dans ton cas c'est l'opérateur = qui sera utilisé, et pas le constructeur par copie, puisque ton objet est déjà construit.

    Dans l'abslu, ebovar _s3 = _s1 << _s2; devrait aussi passer par un opérateur =, mais le compilo est assez malin pour voir qu'il peut utiliser un constructeur par copie.

    Btw, vu que tu fais de l'allocation etc, les fonctions par défaut ne suffiront pas et tu devras les redéfinir.
    http://cpp.developpez.com/faq/cpp/?p...oxe-de-Coplien
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Juin 2008
    Messages
    56
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 56
    Par défaut
    Bon merci.
    Je vais surcharger le =

    par contre, dans le cas du ebovar _s3 = _s1 << _s2;, il n'appelle pas mon constructeur par copie, car j'ai mis dans celui-ci un printf qui n'est pas exécuté.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    	ebovar(const ebovar &source)
    	{
    		printf("++++ create copy of ebovar\n");
    	}
    Donc, il doit faire autre chose.

    Ps: @Capitain'Flam : Merci de t'être fait ch..r a me faire le code J'en demandais pas tant...

  4. #4
    Membre éclairé
    Avatar de Captain'Flam
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2011
    Messages
    273
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Février 2011
    Messages : 273
    Billets dans le blog
    1
    Par défaut
    Hou la la !
    Tu fais des choses très dangereuses toi !
    Si tu ne définis pas l'opérateur = pour une classe, le compilo t'en fabrique un qui invoque les opérateurs = de tous les membres, s'il en ont un, et sinon un memcpy.
    Du coup, ici, comme tu ne définis pas d'opérateur = , tu te retrouves avec 2 pointeurs sur la même string.
    Comme la première est détruite, l'autre pointe sur un objet désalloué, et c'est la mort fatale !

    --> tu dois définir un opérateur = du genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
         const ebovar&operator= ( const ebovar & source )
                {
                if (var_type == EBO_STRING) delete s ;
     
                var_type = source.var_type;
                i        = source.i ;
                if (var_type == EBO_STRING)
                    s = new string( *source.s ) ;
                return *this ;
                }
    et contrairement à ce que tu dis, le constructeur par copie est bien invoqué, et il doit ressembler à ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
            ebovar(const ebovar &source)
                {
                var_type = source.var_type;
                i        = source.i ;
                if (var_type == EBO_STRING)
                    s = new string( *source.s ) ;
                }
    Bien sûr, dans mes exemples, je ne gère pas les autres valeurs de var_type.

    Mais d'une manière générale, il vaut mieux éviter de mélanger du code "à la C" avec unions et pointeurs, et du C++ avec ses stl.
    Il vaut mieux, dans ton cas, définir une classe mère avec une classe dérivée par type de variable contenue.
    Je te laisse méditer la question et revenir poser des questions ici.

  5. #5
    Membre chevronné Avatar de fenkys
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    376
    Détails du profil
    Informations personnelles :
    Âge : 58
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Octobre 2007
    Messages : 376
    Par défaut
    Bonjour,


    C'est assez miraculeux que le premier code fonctionne.

    Ton operator<< crée un objet, cet objet est dupliqué par le constructeur de copie et c'est cette copie temporaire qui est affecté par l'opérateur d'affectation ebovar::operator = (const ebovar &). Puis la copie est detruite.

    Sauf que tu n'as pas défini l'opérateur d'affectation. Le compilateur en genère donc un pour toi, qui fait une copie membre à membre de ton objet source dans celui de destination. Le pointeur ebovar::s est donc recopié tel quel dans l'objet destination. Quand ta copie temporaire est detruite, l'objet pointé par s est également detruit, ton pointeur devient invalide. Quand tu veux afficher ton objet, tu essaies d'accéder à un objet invalide.

    Si tu n'utilisais pas une union pour contenir tes données, tu aurais deux solutions pour résoudre le problème :
    - l'ancienne et complexe : définir ton opérateur d'affectation (qui duplique le pointeur).
    - la nouvelle et facile : remplacer string* s par shared_ptr<string> s dans ebovar. Cet objet compte les références à un objet et ne le détruit que quand il n'est plus utilisé nulle part.

    Mais comme tu utilises une union, il ne te reste que la première.


    Cordialement.

  6. #6
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Juin 2008
    Messages
    56
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 56
    Par défaut
    Bon voilà.

    Merci a tous. Ça fonctionne.
    Doucement je commence à y voir clair...

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

Discussions similaires

  1. Problème constructeur par copie listes chainées
    Par Nicoclem dans le forum C++
    Réponses: 4
    Dernier message: 10/04/2008, 11h44
  2. Petit problème avec le constructeur par copie
    Par beegees dans le forum C++
    Réponses: 16
    Dernier message: 01/04/2008, 16h34
  3. [Debutant] Problème avec un constructeur par copie
    Par Drannor dans le forum Débuter
    Réponses: 5
    Dernier message: 12/03/2007, 09h15
  4. Problème de constructeur de copie ?
    Par Bestiol dans le forum C++
    Réponses: 6
    Dernier message: 03/11/2006, 11h28
  5. Réponses: 15
    Dernier message: 23/06/2006, 13h57

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