Se connecter / S'enregistrer
Votre question

C++ Problème avec opérateur (+)

Tags :
  • chaine
  • Programmation
Dernière réponse : dans Programmation
26 Avril 2010 19:29:59

Bonjour,

Je débute depuis peu en c++ et je bloque actuellement sur un petit exercice dans lequel je souhaite concacténer deux chaines de caractères par le biais d'un opérator+.

  1. #include <iostream>
  2. #include <conio.h>
  3.  
  4. using namespace std;
  5.  
  6. class chaine
  7. {
  8. private :
  9. int _longueur;
  10. char* _chaine;
  11.  
  12. public :
  13. chaine::chaine();
  14. chaine::~chaine();
  15. chaine::chaine(char *texte);
  16. void chaine::operator = (chaine &ch);
  17. int chaine::operator == (chaine ch);
  18. chaine &chaine::operator +(chaine ch);
  19. char &chaine::operator [](int i);
  20. void chaine::affiche();
  21.  
  22. };
  23.  
  24. chaine::chaine() : _longueur(0), _chaine(new char[1]) //constructeur1
  25. {
  26. _chaine[0] = 0;
  27. }
  28.  
  29. chaine::chaine(char *texte) //constructeur2
  30. {
  31. _chaine = texte;
  32. }
  33.  
  34. void chaine::operator = (chaine &ch) //affectation
  35. {
  36. _chaine = ch._chaine;
  37. }
  38.  
  39. int chaine::operator == (chaine ch) //comparaison
  40. {
  41. if (_chaine == ch._chaine)
  42. return 1;
  43. else
  44. return 0;
  45. }
  46.  
  47. chaine &chaine::operator +(chaine ch) //concaténage
  48.  
  49. {
  50. long size = _longueur + ch._longueur;
  51.  
  52. char* tmp = new char[size +1];
  53.  
  54.  
  55. for (long i = 0; i < _longueur; i++)
  56. tmp[i] = _chaine[i];
  57.  
  58.  
  59. for (long i = 0; i < ch._longueur; i++)
  60. tmp[_longueur + i] = ch._chaine[i];
  61.  
  62. tmp[size] = '\0';
  63.  
  64. chaine res(tmp);
  65.  
  66. delete tmp;
  67.  
  68. return res;
  69. }
  70.  
  71. char &chaine::operator [](int i)
  72. {
  73. return _chaine[i];
  74. }
  75.  
  76. chaine::~chaine()
  77. {
  78. }
  79.  
  80. void chaine::affiche()
  81. {
  82. cout << _chaine << endl;
  83. }
  84.  
  85. int main()
  86. {
  87. chaine a("Bonjour "),b("Maria"),c,d("Bonjour "),e;
  88.  
  89. if (a==b) cout << "Gagne !\n";
  90. else cout << "Perdu !\n";
  91. if (a==d) cout << "Gagne !\n";
  92. else cout << "Perdu !\n";
  93. cout << "a: ";
  94. a.affiche();
  95. cout << "b: ";
  96. b.affiche();
  97. cout << "d: ";
  98. d.affiche();
  99. c = a+b;
  100. cout << "c: ";
  101. c.affiche();
  102.  
  103. for(int i=0; c[i]!='\0'; i++)
  104. cout << c[i];
  105. getch();
  106. }




Le programme compile niquel cependant je trouve un bug à cette ligne "char* tmp = new char[size +1];" ce qui est normal puisque mon size est égale à -357767023.

C'est ici que j'ai besoin de votre aide c'est surement une erreur de pointeur mais je ne vois ce que j'ai fais d'incorrect.

Merci d'avance.

Autres pages sur : probleme operateur

26 Avril 2010 20:19:57

T'es bien sur d'initialiser ton _longueur dans ton constructeur à un argument?
m
0
l
a b L Programmation
26 Avril 2010 20:28:55

Déjà remplace: chaine &chaine:: operator +(chaine ch);
par: chaine chaine:: operator +(const chaine & ch);

Avec l'opérateur +, tu instancies un nouvel objet, il ne faut donc pas que tu retourne une simple référence sur un objet local qui sera détruit dans ta méthode!

Pour le paramètre, dans ton cas, un objet temporaire est instancié, et le constructeur par recopie est utilisé. Or, tu n'as pas surchargé de constructeur par recopie, donc ça fait une recopie binaire (_chaine n'est pas recopié, c'est juste l'adresse qui l'est, donc ça pointe sur le même buffer !).
En faisant passer une référence constante, il n'y a pas de copie puisque c'est l'objet direct que tu passes, et tu ne prends pas le risque de modifier son contenu (le compilateur te l'empêcheras).

Bref, c'est un gros problème, mais qui n'est pour l'instant pas visible dans ton programme actuel.

Ton problème vient du contenu de ta méthode surchargeant l'opérateur d'addition.
Pour résumer, ce que tu fais:
1. Tu alloues un nouveau buffer
2. lors de l'instanciation de res, res ne contient que le pointeur sur le buffer, il ne réalloue rien, donc est dépendant de la vie du buffer
3. L'instanciation de res est local, elle sera donc détruite à la fin de la méthode.
4. tu fais un "delete tmp", donc, tu désalloues le buffer, qui est aussi le buffer dans res. Donc, tu désalloues le buffer contenu dans res.
5. Tu retournes res en référence, et implicitement, comme c'est une variable locale, l'instance res est désalloué.
Donc, au final, tu retournes un objet détruit, qui de toutes façons, avait un buffer désalloué.
Si tu fais retourner, un objet et pas une référence, l'objet est copié (via son constructeur par recopie), mais là tu tombes dans le problème que j'ai cité plus haut, à savoir que le buffer n'est pas copié, c'est juste l'adresse mémoire qui l'est.

Donc, pour résumer (buffer=_chaine):
1. Faire un constructeur par recopie qui copie tout ce qui est pointeur et référence (bref ta chaine), pour être sûr qu'une instance copiée ne pointe pas sur le buffer de l'autre instance mais sur son nouveau buffer
2. Modifier ton constructeur avec char * en paramètre, et faire une copie du buffer
3. Modifier tous les contructeurs pour gérer l'allocation du buffer
4. Modifier ton destructeur pour gérer la désallocation du buffer
5. Faire passer en paramètre de + une référence constante (autant éviter une copie de buffer inutile)
6. Faire retourner une instance de chaine (une copie de la variable locale que tu vas créer)
7. Créer un tmp, mais désallouer le buffer en cours d'utilisation, pas tmp !
8. Créer ton tmp comme tu l'a fait, le donner à ton constructeur que tu as modifié pour faire une copie, et supprimer tmp (puisqu'il aura été copié par ton nouveau constructeur).
9. retourner l'objet local qui sera implicitement recopié pour l'appelant (par le constructeur par recopie que tu auras implémenté). La variable locale sera détruite grâce au destructeur que tu auras modifié.
10. Et j'allais oublier, corrige ton opérateur = pour désallouer l'ancien buffer, en créer un nouveau, et faire une copie de buffer.

Tout ça, ce sont des automatismes à avoir pour tout codage en C++.
m
0
l
Contenus similaires
27 Avril 2010 00:07:21

Merci pour vos réponses, une seul chose que je n'ai pas mentionné c'est que les prototypes sont imposés par l'exercice après je ne sais pas si c'est une erreur d'énoncé.

Sinon je vais essayer d'appliquer ce que tu m'as dis CRicky merci.

:) 
m
0
l
a b L Programmation
27 Avril 2010 20:45:37

Alors, celui qui a fait l'énoncé n'est pas un bon programmeur C++.
m
0
l
27 Avril 2010 23:15:21

:D  c'est un prof après je connais pas ses diplômes

sinon j'ai réussi à faire mon opérateur+

  1. chaine &chaine::operator +(chaine ch)
  2. {
  3. size_t size = _longueur + ch._longueur;
  4.  
  5. char* tmp = new char[size +1];
  6.  
  7. for (size_t i = 0; i < _longueur; i++)
  8. tmp[i] = _chaine[i];
  9.  
  10. for (size_t i = 0; i < ch._longueur; i++)
  11. tmp[_longueur + i] = ch._chaine[i];
  12.  
  13. tmp[size] = '\0';
  14.  
  15. delete[] _chaine; // detruit la zone mémoire pointée par _chaine avant de changer pour la nouvelle adresse
  16.  
  17. _chaine = tmp; // changement d'adresse du pointeur
  18.  
  19. return *this;
  20. }


Parcontre nouveau problème j'ai un soucis pour désalloueur l'adresse mémoire ou pointe _chaine "delete[] _chaine;"
m
0
l
a b L Programmation
28 Avril 2010 20:44:27

En fait, là tu redéfinis l'opérateur "+=". En même temps, si tu n'as pas eu de directive pour la fonctionnalité de cet opérateur, alors tu peux faire ce que tu veux. :) 

Pour ton problème, est-ce que tu as fait une allocation dans tous les constructeurs ? parce que si tu fais un delete sur un pointeur non alloué, une exception sera soulevée.
m
0
l
Tom's guide dans le monde
  • Allemagne
  • Italie
  • Irlande
  • Royaume Uni
  • Etats Unis
Suivre Tom's Guide
Inscrivez-vous à la Newsletter
  • ajouter à twitter
  • ajouter à facebook
  • ajouter un flux RSS