problème avec le constructeur de copie - C++ - Programmation
Marsh Posté le 01-02-2011 à 16:32:49
Dans le code que tu as poste, il y a deux fois le meme constructeur. J'imagine que tu as un constructeur par defaut et un constructeur prenant deux parametres.
Le compilateur devrait creer un constructeur de recopie par defaut ... Mais dans ton cas, il ne sera pas bon car, les pointeurs m_arme "pointront" vers la meme "arme" (le constructeur par defaut se contentant de copier coller les valeurs des membres de l'objet copie). Il faut donc que tu definisses un constructeur de recopie faisant une copie correct des pointeurs (donc au moins de m_arme).
Marsh Posté le 01-02-2011 à 17:34:49
Le problème est résolu. En fait j'ai déclaré le constructeur de copie mais je ne l'ai pas défini ...
Sinon un autre problème toujours lié au constructeur de copie ( et donc tu as parlé un peu dans ta réponse ) :
-- j'ai deux Personnage david et goliath qui ont un pointeur arme pointant vers le meme objet arme (voir main ci-dessus).
-- j'ai détruit david ( d'abord son arme, puis lui meme ), puis j'ai détruit goliath et ceux en fin de main( )
Code :
|
Ma question :
est-ce normal que le compilateur ne rale pas, que le programme ne plante pas ... ?
En effet quand je détruit goliath l'arme disparait avec lui. Quand je tente de détruire david, le compilateur est censé cherche son arme ... NON ?
Merci d'avance pour votre aide.
Marsh Posté le 01-02-2011 à 17:43:14
razuki a écrit :
|
Comment supprimes-tu des objets, toi ? "delete", ca te parle ?
Poste un peu le code de ton destructeur, pour voir.
Marsh Posté le 01-02-2011 à 17:50:26
Code :
|
Marsh Posté le 01-02-2011 à 18:26:14
Pour l'instant, je ne vois pas d'où vient ce prodige, mais j'ai deux remarques à faire :
1) On n'appelle JAMAIS un destructeur directement. Il faut toujours passer par "delete". Je parierai que si tu remplace tes deux horribles appels aux destructeurs par des "delete" en bonne et due forme, ton programme va se planter comme tu t'y attends.
2) L'opérateur "delete" fait deux choses : il invoque le destructeur de l'objet ET il libère la mémoire occupée par cet objet.
Si dans ta fonction ~Personnage() tu avais appelé m_arme->~Arme() au lieu de faire un "delete m_arme", l'espace mémoire occupé par m_arme n'aurait pas été libéré, donc ca aurrait pu expliquer pourquoi ca ne posait pas de souci de "détruire" cette ressource commune.
Marsh Posté le 01-02-2011 à 21:20:17
Dans ton constructeur par copie, ce n'est pas l'adresse de "arme" que tu dois dupliquer, mais l'objet "arme". Chaque objet Personnage doit avoir sa propre "arme".
Marsh Posté le 02-02-2011 à 00:42:40
J'ai vu quelque part que le compilateur fait appel implicitement au destructeur. C'est ce que shaoyin voulait me dire ppeut etre dans son 1). J'ai aussi essayé de ne pas mettre les deux lignes ci-dessous au début, mais le compilateur ne rale pas non plus. Je m'attendais à ce qu'il rale.
1. goliath.~Personnage();
2. david.~Personnage();
Marsh Posté le 02-02-2011 à 00:54:48
Si j'ai bien compris :
1) le compilateur (?) détruit implicitement systématiquement david et goliath avant de terminer le programme.
2) Je n'ai donc pas besoin de faire appel au destructeur.
david utilise une arme A, goliath utilise la meme arme A. Les deux pointent sur le meme objet A.
-- le compilateur (?) détruit implicitement systematiquement david ET donc son arme => OK
-- le compilateur (?) détruit implicitement systematiquement goliath MAIS il ne trouve pas l'arme de celui-ci car l'arme a été détruite avec david ...
Pourquoi le compilateur ne rale pas ?
Marsh Posté le 02-02-2011 à 01:13:10
razuki a écrit : Si j'ai bien compris : |
1) Oui chaque variable est detruite lorsqu'elle sort du scope:
Code :
|
2) on n'appelle jamais un destructeur manuellement. Par contre, tu DOIS utiliser "delete" pour liberer memoire allouee par "new", celui-ci se chargera d'appeler le destructeur (ou les destructeurs en cas d'heritage)
Ensuite le compilateur en tant que tel ne te dira jamais rien sur ce genre de probleme (ca serait trop facile ), c'est a l'execution que ca plantera (memoire corrompue). Ce code devrait planter:
Code :
|
Marsh Posté le 02-02-2011 à 09:56:19
xilebo a écrit : Dans ton constructeur par copie, ce n'est pas l'adresse de "arme" que tu dois dupliquer, mais l'objet "arme". Chaque objet Personnage doit avoir sa propre "arme". |
Pas forcément, s'il y a beaucoup de personnages et une banque de données d'arme, et que chaque personnage ne modifie pas sa propre arme il aurait meilleur compte à implémenter une classe de banque d'armes qui instancie les armes utilisées sur demande, et à fournir à chaque personnage une fonction donnant accès à une référence vers une arme constante :
Code :
|
Marsh Posté le 02-02-2011 à 09:56:56
Dans tous les cas, les pointeurs bruts c'est la porte ouverte à toutes les fenêtres, c'est pas la la solution ici.
Marsh Posté le 02-02-2011 à 10:50:23
hephaestos a écrit : Dans tous les cas, les pointeurs bruts c'est la porte ouverte à toutes les fenêtres, c'est pas la la solution ici. |
Marsh Posté le 02-02-2011 à 11:59:09
Bonjour,
Je débute en C++ et j'aimerais provoquer des erreurs justement à l'exécution pour voir comment ca fonctionne.
Voici mon code Personnage.h :
Code :
|
Voici mon code Personnage.cpp :
Code :
|
Mon main :
Code :
|
le résultat après execution :
Code :
|
Donc là le programme ne plante pas, contrairement à quoi je m'attendais.
Marsh Posté le 02-02-2011 à 13:53:24
Hum... d'un côté, ton programme est en train de se terminer lorsque se passe la double destruction du champ "m_arme". Alors le plantage n'est peut-être pas vraiment mis en évidence.
Tu peux essayer de mettre tout le contenu de ta fonction "main" (sauf le 'return 0;') dans un bloc, et de faire d'autres choses après ce bloc (des écritures sur std::cout, par exemple).
Marsh Posté le 02-02-2011 à 14:06:15
C'est bizarre que tu te retrouves avec deux armes différentes alors qu'effectivement ton constructeur de copie garde le même pointeur...
Marsh Posté le 02-02-2011 à 14:08:06
J'avais pas fait gaffe à ca...
Marsh Posté le 02-02-2011 à 14:08:59
Oui, et il devrait aussi changer l'arme de David quand il change l'arme de Goliath, et ce n'est pas le cas.
Marsh Posté le 02-02-2011 à 14:14:51
razuki, tu peux poster le code de ta classe "Arme", stp ?
Marsh Posté le 02-02-2011 à 14:34:37
shaoyin > j'ai regroupé toutes les instructions dans main( ) ( sauf return 0 ) dans un bloc. Puis j'ai rajouté un cout << "test" à l'extérieur du bloc. Effectivement il n'affiche pas "test" quand David et Goliath possèdent le meme objet arme. Par contre, "test" s'affiche bien quand les deux personnages possède deux objets armes différents.
Hephaestos> moi non plus j'ai pas remarqué qu'il n'a pas changé l'arme de David ...
Je vais voir plutard et je vous tiendrai au courant.
Marsh Posté le 02-02-2011 à 15:04:09
Je serais bien curieux de voir le code de la classe Arme, car avec le code que tu as poste, je ne vois pas comment David peut garder son arme (je ne peux meme pas imaginer comment realiser cela avec le code du constructeur de recopie que tu as).
Es tu sur que tu as poster le bon code pour Personnage, car si tu as :
Code :
|
(qui est en commentaire), ca marchera.
PS1: Pour les arguments de type std::string, utiliser une reference constante (i.e const std::string& ) est presque toujours une bonne idee!
PS2: Rendre les methodes constantes (par exemple afficherEtat()) est aussi une bonne pratique
Marsh Posté le 02-02-2011 à 15:14:42
.h
Code :
|
.cpp
Code :
|
Marsh Posté le 02-02-2011 à 15:36:35
Rien de bien extraordinaire la dedans.
Es-tu sur de ta sortie? car ca n'a pas de sens pour moi ...
Marsh Posté le 01-02-2011 à 16:01:11
Bonjour,
J'ai défini un classe Personnage. J'essaie de copier le Personnage goliath vers le Personnage david comme suit :
Voici les constructeurs que j'ai crée dans la classe Personnage :
Le compilateur me dit alors :
Undefined reference to 'Personnage::Personage(Personnage const& )
Ma question :
-- Le compilateur ne crée - t - il pas automatiquement le constructeur de copie ?
-- le problème serait - il ailleurs ?
Merci d'avance pour votre aide.
Message édité par razuki le 01-02-2011 à 17:51:52