Surcharge de l'opérateur = + Appel non souhaité à delete

Surcharge de l'opérateur = + Appel non souhaité à delete - C++ - Programmation

Marsh Posté le 20-07-2007 à 15:54:33    

Bonjour,
 
J'ai créé une classe Article qui contient un pointeur sur une zone mémoire alloué.
Par propreté, j'ai donc créé un opérateur de destruction de cette zone pour éviter de bloquer la mémoire lorsque ces objets ne sont plus utilisé :
 

Code :
  1. class Article
  2. {
  3. ~Article()
  4. {
  5. delete [] tabdoub;
  6. }
  7. double* tabdoub;
  8. }


 
J'ai également créé un opérateur d'égalité afin de créer un objet "Article" de contenu identique à un autre.
Pour cela, bien évidemment, j'ai une boucle qui parcourt le tableau tabdoub et recopie tous ses éléments dans le nouvel objet :
 

Code :
  1. void Article::operator=(Article art_orig)
  2. {
  3. //recopie des éléments du tableau tabdoub de art_orig
  4. // après l'allocation dynamique nécessaire
  5. }


 
Tous cela fonctionne bien jusqu'à la fin de l'opérateur. Mais valgrind m'a signalé une erreur qui m'a échapé. En effet, par exemple, si dans le code,  j'écris :
 

Code :
  1. Article art1,art2;
  2. ...
  3. art2 = art1;


 
L'article art2 devient bien une copie de art1, mais, à la fin de l'appel à cet opérateur d'égalité, dans la procédure de recopie, le destructeur ~Article est appelé pour détruire la copie de art1 passé en argument de l'opérateur d'égalité (ie. art_orig). Ce destructeur détruit alors la zone alloué au tableau tabdoub de art_orig qui se trouve être la même que celle de art1 ! Ainsi, le contenu du tableau de art1 est également une zone mémoire effacée car elle est indentique à celle de art_orig !
 
 
Comme éviter ce problème ? Je souhaiterais quand même, par propreté, conserver ce destructeur qui est, normalement, nécessaire.
J'espère avoir été à peu près clair dans mes explications.
 
Cordialement

Reply

Marsh Posté le 20-07-2007 à 15:54:33   

Reply

Marsh Posté le 20-07-2007 à 16:39:38    

Bonjour,
 
Est-ce que tu pourrais préciser ceci ?

Code :
  1. void Article::operator=(Article art_orig)
  2. {
  3.       //recopie des éléments du tableau tabdoub de art_orig
  4.       // après l'allocation dynamique nécessaire
  5. }

Merci  :)

Reply

Marsh Posté le 20-07-2007 à 16:49:57    

Bonjour,
 
Je veux simplement mentionner que l'opérateur d'égalité est écrit comme :
 

Code :
  1. void Article::operator=(Article art_orig)
  2. {
  3. int i;
  4. nmax = art_orig.val_nmax(); // Valeur du nombre maximal de points contenu dans le tableau tabdoub. Il s'agit d'un membre de art_orig auquel val_nmax() est la méthode d'accès
  5. for(i=0;i<nmax;i++)
  6. {
  7. tabdoub[i] = art_orig.val_tabdoub(i);    // Valeur du ième élément du tableau tabdoub de art_orig, l'article dont on cherche à faire une copie dans this
  8. }
  9. // Avant la sortie de l'opérateur , un appel par défaut au destructeur de Article et appliqué à art_orig est appelé
  10. // Il détruit le pointeur tabdoub de art_orig qui pointe vers la même zone que art1
  11. // Il n'y a donc pas conservation des valeurs du tableau tabdoub de art1
  12. }


 
Est-ce que mon problème est un peu plus claire ?
Il y a sans doute plusieurs solutions à ce problème mais je voidrais essayer de trouver quelque chose le plus propre possible.
 
Cordialement

Reply

Marsh Posté le 20-07-2007 à 17:01:01    

Ajoute un constructeur de copie

Code :
  1. Article::Article(const Article & art_orig)

et transforme ton

Code :
  1. void Article::operator=(Article art_orig)

en

Code :
  1. void Article::operator=(const Article & art_orig)


Ca devrait aller mieux apres :).
 
edit: vire le void foireux....

Message cité 1 fois
Message édité par jojolepingouin le 20-07-2007 à 17:34:45
Reply

Marsh Posté le 20-07-2007 à 17:23:39    

OK, je vais vérifier mais quel est l'intérêt d'un constructeur de copie par rapport à l'opérateur =.
 
Les deux réalise le même travail, non ? :
 
art2 = Article(art1);
art2 = art1;
 
sont deux écritures équivalentes ?
 
Est-ce que ton constructeur par recopie sera appelé lors de l'utilisation de l'opérateur " = " et permettra de faire une copie de art1 sous la forme de art_orig, avec des zones mémoires allouées distinctes entre ces deux objets ?
 
Merci déjà de ton aide,

Reply

Marsh Posté le 20-07-2007 à 17:34:14    

Bah comme dirait Taz (en moins diplomatique bien sur), surcharger l'operateur= sans refaire un constructeur de copie ca sert juste a chopper des vieux bugs (un peu comme si on redefinit operateur+ sans refaire operateur+=).
 
Donc tu fais ca:

Code :
  1. Article::Article(const Article & art_orig)
  2. {
  3.    (*this) = art_orig;
  4. }

Et apres ca marchera mieux.
 
Sinon pour ton bug, tu passes art_orig en copie ici, donc ca appelle le constructeur de copie par défaut de ton Article(qui copie juste le pointeur), a la fin de ta methode, art_orig est détruit par ton destructeur et donc t'as tout corrompu.

Code :
  1. void Article::operator=(Article art_orig)

Reply

Marsh Posté le 20-07-2007 à 17:47:59    

Merci de ces précisions mais, maintenant j'ai un stackoverflow en message d'erreur et je n'arrive même pas à entrer dans l'opérateur d'égalité ! Le programme s'arrête avant !
 
J'ai bien compris d'où venait mon problème initial, de la destruction d'une zone mémoire que j'utilisais par la suite comme tu le précises.
 
Par rapport à ce nouveau problème, est-ce que je dois conserver l'opérateur d'égalité et le constructeur par recopie ?
De toutes façons, tant que le destructeur sera appelé sur un objet que j'utilise, j'aurais un problème.

Reply

Marsh Posté le 20-07-2007 à 17:51:12    

un opérateur d'affectation ne retourne pas void, et il faut gérer l'affectation d'un élément à lui-même ...

Reply

Marsh Posté le 20-07-2007 à 18:06:33    

theshockwave a écrit :

un opérateur d'affectation ne retourne pas void, et il faut gérer l'affectation d'un élément à lui-même ...


C'est vrai qu'il faut aussi faire gaffe a ca...


Message édité par jojolepingouin le 20-07-2007 à 18:06:51
Reply

Marsh Posté le 23-07-2007 à 00:59:36    

jète. utilise std::vector<double>

Reply

Marsh Posté le 23-07-2007 à 00:59:36   

Reply

Marsh Posté le 23-07-2007 à 14:45:49    

theshockwave a écrit :

un opérateur d'affectation ne retourne pas void, et il faut gérer l'affectation d'un élément à lui-même ...


et il prend une référence en parametre :o

Reply

Marsh Posté le 23-07-2007 à 14:51:30    

KangOl a écrit :


et il prend une référence en parametre :o


 
ca avait déjà été suggéré :o
 

jojolepingouin a écrit :

Code :
  1. void Article::operator=(const Article & art_orig)


Reply

Marsh Posté le 23-07-2007 à 14:52:28    

beurl le void

Reply

Marsh Posté le 23-07-2007 à 14:53:54    

Taz a écrit :

beurl le void


j'vais pas me justifier d'un code que je copie colle et que j'ai déjà critiqué plus haut juste parce que tu n'as pas lu mon message  :kaola:  
 
 
;)

Reply

Marsh Posté le 23-07-2007 à 15:10:18    

putain mais elle me saoule ma touche k !

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed