C++ et pointeurs, problème pour désalouer...

C++ et pointeurs, problème pour désalouer... - C++ - Programmation

Marsh Posté le 08-04-2009 à 17:35:52    

Bonjour à tous et toutes, j'aurais besoin de votre aide pour comprendre le "pourquoi" du comment.
 
Je développe en C++ QT, et j'ai une application principale qui lance un thread de calcul qui va envoyer des signaux à ma fenêtre principale.
Tout ça marche parfaitement.
Bon dans un but d'optimisation, je cherche à supprimer ce que je créais pour ne pas réalouer à chaque fois et perdre en mémoire.
 
Mon programme me permet de rechercher une chaine de caractère dans chaque ligne des documents listés dans un dossier.
 
Voici donc les éléments qui posent problème:
Mon thread la boucle run

Code :
  1. [...]//Diverses choses inutiles dans le contexte puisque pas de pointeur
  2. //Variables
  3. bool contient=false;
  4. int nbOcc=0;
  5. QTableWidgetItem * item1=new QTableWidgetItem("" );//Pas utile je sais mais c'était pour vérifier
  6. QTableWidgetItem * item2=new QTableWidgetItem("" );
  7. foreach (QString s,currentDir.entryList())
  8. {
  9.    [...] //parcour des fichiers
  10.  if (contient)
  11.  {
  12.   char tmp2[33];
  13.   //Création d'une ligne d'enregistrement
  14.   item1=new QTableWidgetItem(s);
  15.   itoa(nbOcc,tmp2,10);
  16.   item2=new QTableWidgetItem(tmp2);
  17.   emit addRow(item1,item2);//Lance addRow du programme principal,Ajout de l'item dans le tableau de la fenêtre principale, le problème peut venir de là.
  18.  }
  19.  emit update();//Juste pour mettre à jour la progressbar
  20. }
  21.            //Le problème est ici! Si je délete item1 et item2, si je relance trop vite en reclicant sur le bouton rechercher, mon application se plante. Si je met en commentaire ces deux lignes ce n'est pas le cas.
  22. delete item1;
  23. delete item2;
  24. emit terminate();//lance finish du programme principal


 
Ma dans mon programme principal, mes slots:

Code :
  1. bool DialogImpl::search()
  2. {
  3. pushButtonRechercher->setEnabled(false);//Je désactive bien le bouton dès le début...
  4. tableResult->clearContents();
  5. for (int i=tableResult->rowCount()-1; i >= 0; --i)
  6.   tableResult->removeRow(i);
  7. m_recherche= new Recherche (m_rep,this,lineEditText->text());
  8. m_recherche->start();
  9. //m_progress.hide();
  10. return true;//pas propre je sais, reste d'une ancienne bidouille
  11. }
  12. void DialogImpl::finish()
  13. {
  14. m_progress.hide();
  15. m_recherche->wait();
  16. pushButtonRechercher->setEnabled(true);
  17. delete m_recherche;//avec ou sans ça ça ne change pas le problème de crash
  18. }
  19. void DialogImpl::addRow(QTableWidgetItem * item1,QTableWidgetItem * item2)
  20. {
  21.   int row=tableResult->rowCount();
  22.   tableResult->insertRow(row);
  23.   tableResult->setItem(row,0,item1);
  24.   tableResult->setItem(row,1,item2);
  25. }


Si j'enlève les:
delete item1;
delete item2;
plus de plantage, ma question est pourquoi donc?
Je précise qu'avec les delete ça marche quand même, mais si je clique trop rapidement sur le bouton rechercher du genre "mode bourin à cliquer moulte fois :D" l'application se crash, alors que sans les delete non. Est ce grave de ne  pas désalouer? Les news désalouent ils les anciennes valeurs?


Message édité par burn2 le 08-04-2009 à 17:43:26

---------------
"C'est vrai qu'un type aussi pénible de jour on serait en droit d'espérer qu'il fasse un break de nuit mais bon …"
Reply

Marsh Posté le 08-04-2009 à 17:35:52   

Reply

Marsh Posté le 08-04-2009 à 17:42:13    

Une petite question d'ailleurs, en admetons que ça soit possible.
Si je fais:

Code :
  1. int * test;
  2. test=new int (10);
  3. test=new int (15);


Entre les deux new, la mémoire est elle bien désalouée ou il faut que je fasse un delete test?


Message édité par burn2 le 08-04-2009 à 17:42:31

---------------
"C'est vrai qu'un type aussi pénible de jour on serait en droit d'espérer qu'il fasse un break de nuit mais bon …"
Reply

Marsh Posté le 08-04-2009 à 17:57:57    

v_v on est pas en java. 1 new = 1 delete.
 
et tu sais que new int(10) construir *1* int qui vaut 10 et pas 10 int :o

Reply

Marsh Posté le 08-04-2009 à 18:42:31    

Oui je sais, mais là c'était une question avec l'exemple le plus "pourite" possible pour bien être sûr.
 
Sinon dans mon code alors c'est quoi qui cloche, pourquoi si je met le delete ça ne marche plus instantanément??? :??:


---------------
"C'est vrai qu'un type aussi pénible de jour on serait en droit d'espérer qu'il fasse un break de nuit mais bon …"
Reply

Marsh Posté le 08-04-2009 à 19:31:44    

la question ets de savoir si addrow ne transfere pas l'ownership des objets au conteneru, ce qui fait que lorsque le conteneur est detruit, il fait le delete deja.
 
Rajoute un if(item1) delet item1; pour voir

Reply

Marsh Posté le 08-04-2009 à 19:34:30    

Oui c'est ce que je me disais, mais le problème, c'est que ça se crash au tout début du relancement, je n'ai même pas le temps de voir la bare de chargement que vlam. Et le delete est totalement à la fin du processus après avoir parcourus tous les fichier, donc avoir vu la bare de progression et qu'elle soit arrivée à 100%. Donc ce n'est pas possible. Là ça se crashe au premier tour de boucle au relancement visiblement.  
il faudrait que je me mette en mode debug pour suivre ou ça crash, mais j'aimerais bien en avoir la cause.  
Pour moi c'est dans le thread au relancement que ça se crash et non pas ailleurs.
 
Or comme vous pouvez le constater je ne peux recliquer sur le bouton pour relancer que quand le thread est bien terminé et que tout est bien stoppé. Donc j'avoue ne pas comprendre pourquoi si je vais trop vite ça crash, mais si j'attends un tout petit moment ça passe.  
 
 
EDIT: ça le fait autant sous xp que sous vista, par contre sous vista j'ai une protection contre la prévention des données, je me demande si ce n'est pas une protection de l'os contre un "je désaloue via delete, et j'alloue rapidement sans new par un programme en un temps trop rapide".


Message édité par burn2 le 08-04-2009 à 19:40:40

---------------
"C'est vrai qu'un type aussi pénible de jour on serait en droit d'espérer qu'il fasse un break de nuit mais bon …"
Reply

Marsh Posté le 08-04-2009 à 21:13:55    

Joel F a écrit :

v_v on est pas en java. 1 new = 1 delete.
 
et tu sais que new int(10) construir *1* int qui vaut 10 et pas 10 int :o


Et bien non, en fait ce que tu dis est totalement faux....
Un test tout c**:
int *test;
while (1)
test = new int (10);
 
regarde l'utilisation de ta ram...
 
Bon par contre j'ai peut-être une idée de mon pb et pourquoi j'avais pas de fuite mémoire sans delete que j'ai de toute façon mal placé là...


---------------
"C'est vrai qu'un type aussi pénible de jour on serait en droit d'espérer qu'il fasse un break de nuit mais bon …"
Reply

Marsh Posté le 08-04-2009 à 21:40:40    

je pense que non. Si t'arrive à voir l'effet d'une allocation de 4 octets dans ton moniteur de ram t'es super fort meme comme ça.
 
Alloue en boucle 1Mo et on en reparle

Reply

Marsh Posté le 08-04-2009 à 21:44:46    

burn2 a écrit :


Et bien non, en fait ce que tu dis est totalement faux....
Un test tout c**:
int *test;
while (1)
test = new int (10);
 
regarde l'utilisation de ta ram...
 
Bon par contre j'ai peut-être une idée de mon pb et pourquoi j'avais pas de fuite mémoire sans delete que j'ai de toute façon mal placé là...


 
 
joli memory leak que voilà. Tu alloues en boucle sans désallouer. Bien sur, 4 octets par 4 octets tu vas mettre longtemps à la remplir. Comme le dit Joel F : un new = un delete TOUJOURS.
 

Reply

Marsh Posté le 08-04-2009 à 22:33:37    

Et pour ce qui est des objets, les désallocations dans le sens inverse des allocations pour éviter les bugs dûs à d'éventuelles dépendances entre objets (surtout quand il y a du nettoyage dans les destructeurs).
ex: si une classe initialise une ressource et clôt la ressource dans son destructeur, et qu'une autre classe peut utiliser la ressource une fois ouverte, on construit la première classe, puis la 2e, mais la destruction devra se faire dans le sens inverse des new.


Message édité par el muchacho le 08-04-2009 à 22:37:49

---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
Reply

Marsh Posté le 08-04-2009 à 22:33:37   

Reply

Marsh Posté le 08-04-2009 à 22:43:07    

ouais enfin là c'est que tu as violé le principe d'inversion de responsabilité et de propriété.

Reply

Marsh Posté le 08-04-2009 à 22:53:36    

Joel F a écrit :

la question ets de savoir si addrow ne transfere pas l'ownership des objets au conteneru, ce qui fait que lorsque le conteneur est detruit, il fait le delete deja.
 
Rajoute un if(item1) delet item1; pour voir


delete teste déjà si le pointeur est NULL, comme free(), pas besoin de le tester en ammont
if( p ) delete p;
est équivalent mais redondant face à simplement :
delete p;
 
et c'est standard, ça ne dépend pas de l'implémentation.

Reply

Marsh Posté le 08-04-2009 à 22:56:05    

je la note celle là :) merci

Reply

Marsh Posté le 09-04-2009 à 08:40:41    

Joel F a écrit :

je pense que non. Si t'arrive à voir l'effet d'une allocation de 4 octets dans ton moniteur de ram t'es super fort meme comme ça.
 
Alloue en boucle 1Mo et on en reparle


Et pourtant, je le vois bien sur mon moniteur system. Vu la vitesse de la ram c'est parfaitement normal...  
Avec cette boucle j'alloue une infinitée d'entier, car un new!=delete, donc le précédent int déclaré est toujours valable!
Du coup en boucle infinie ça se remplie très très rapidement! (du genre une pente à 45% et la ram qui se remplie jusqu'a 80% de 2go en 2/3s maximum. Je vous ferais un screen.
 
Je vois la ram se remplir quasi totalement, je n' pas laissé jusqu'au bout, mais teste et tu verras qu'il faut pour chaque new un delete sans quoi la précédente variable pointée n'est pas détruite...


Message édité par burn2 le 09-04-2009 à 08:48:18

---------------
"C'est vrai qu'un type aussi pénible de jour on serait en droit d'espérer qu'il fasse un break de nuit mais bon …"
Reply

Marsh Posté le 09-04-2009 à 08:41:04    

xilebo a écrit :


 
 
joli memory leak que voilà. Tu alloues en boucle sans désallouer. Bien sur, 4 octets par 4 octets tu vas mettre longtemps à la remplir. Comme le dit Joel F : un new = un delete TOUJOURS.
 


Si c'est le cas alors j'avais très mal compris son oui, car je l'avais pris par un new = delete et il n'y a pas besoin d'en faire entre.

jesus_christ a écrit :


delete teste déjà si le pointeur est NULL, comme free(), pas besoin de le tester en ammont
if( p ) delete p;
est équivalent mais redondant face à simplement :
delete p;
 
et c'est standard, ça ne dépend pas de l'implémentation.


pas sûr! Si tu fais:
int * test ;
test= new int(10);
delete test;
delete test;
au deuxième délete ça va se cracher!
 
 
Par contre je pense avoir trouvé la cause de mon problème, dixit ce que m'a dit un pote et avec cette info, j'ai une idée du problème... Je teste ça dessuite.

Message cité 1 fois
Message édité par burn2 le 09-04-2009 à 08:46:38

---------------
"C'est vrai qu'un type aussi pénible de jour on serait en droit d'espérer qu'il fasse un break de nuit mais bon …"
Reply

Marsh Posté le 09-04-2009 à 08:49:01    

burn2 a écrit :


pas sûr! Si tu fais:
int * test ;
test= new int(10);
delete test;
delete test;
au deuxième délete ça va se cracher!
 
 
Par contre je pense avoir trouvé la cause de mon problème, dixit ce que m'a dit un pote et avec cette info, j'ai une idée du problème... Je teste ça dessuite.


 
Ce n'est pas ce qu'il a dit.
 
Tu n'as pas besoin de tester si ton pointeur est NULL. Par contre, quand tu fais un delete sur un pointeur, le delete (ou le free) ne change pas la valeur du pointeur (accessoirement ici, tu aurais rajouté le test que ça n'aurait rien changé.). Ainsi, si tu rappelles delete derrière sur le même pointeur -> comportement indéterminé.
 
Généralement, après un delete ou un free, on met le pointeur à NULL.
 


Message édité par xilebo le 09-04-2009 à 08:50:01
Reply

Marsh Posté le 09-04-2009 à 08:54:15    

Bon en fait ce n'est même pas le même problème que je pensais.  
L'idée que j'avais et que m'avait donné un collègue c'était que dans le tableau, le clear delete tout seul les espaces alouées. Et en fait en l'enlevant le problème est le même.  
 
Concrètement, le problème que j'ai après avoir testé:
Si j'enlève mon clear, laisse les deux deletes à la fin (inutile mais bon je voudrais comprendre pourquoi), le programme se plante toujours à la 3ème exécution de la fonction. Toujours à la 3ème.
Je continue mes tests pour comprendre un peu plus...


---------------
"C'est vrai qu'un type aussi pénible de jour on serait en droit d'espérer qu'il fasse un break de nuit mais bon …"
Reply

Marsh Posté le 09-04-2009 à 09:00:07    

Putain mais quand je dis 1 new = 1 delete, ca veut dire qu'il faut faire un delete pour chaque new [:prozac]
 
TOn probleme viens que ton conteneur doit prendre la propriété des pointeurs et les delet lui même sans les mettre à NULL. Quant tu passes dessus avec les tiens, tu desalloue n'imp.

Reply

Marsh Posté le 09-04-2009 à 09:00:24    

Bon j'ai isolé le problème:
J'ai testé avec:
delete item1;
item1=NULL;
delete item2;
item2=NULL;
 
Le problème ne change pas, par contre je viens de comprendre un truc:
En fait le problème vient de là:

Code :
  1. for (int i=tableResult->rowCount()-1; i >= 0; --i)
  2.   tableResult->removeRow(i);


automatiquement, la boucle désaloue les items et les delete ce qui explique que je n'ai pas de fuite de mémoire dans mon programe sans les deletes. Si j'enlève cette partie, je n'ai plus le plantage.
 
Ce que je ne comprend pas, c'est pourquoi malgrès mon ajout du pointeur null, pourquoi ça se plante toujours à la 3ème exécution même si je delete deux fois un pointeur puisque delete teste si c'est null selon vous. (pour quoi ça repasse la 2ème en fait dans le cas ou c'est une question de pointeur pas passé à null)

Joel F a écrit :

Putain mais quand je dis 1 new = 1 delete, ca veut dire qu'il faut faire un delete pour chaque new [:prozac]
 
TOn probleme viens que ton conteneur doit prendre la propriété des pointeurs et les delet lui même sans les mettre à NULL. Quant tu passes dessus avec les tiens, tu desalloue n'imp.


Tu conviendras que c'était ambigüe tout de même :D
 
Oui le conteneur désaloue tout seul en fait, mais ce que je ne comprend pas c'est pourquoi ça passe 2 fois mais pas 3?  
 


Message édité par burn2 le 09-04-2009 à 09:02:47

---------------
"C'est vrai qu'un type aussi pénible de jour on serait en droit d'espérer qu'il fasse un break de nuit mais bon …"
Reply

Marsh Posté le 09-04-2009 à 09:15:57    

Cela dit, je ne sais toujours pas pourquoi ça cloche. :/
 
Bilan du topic:
J'ai avancé un peu, j'ai compris que tableResult->removeRow(i); deleté tout seul les items donc il est inutile de les supprimer de l'autre côté, mais ma question, c'est même si c'est inutile pourquoi ça se plante à la 3ème et pas la deuxième.
Si c'était une histoire de pointeur pas passé à null dans la fonction de QT automatique, ça ne marcherait même pas à la 2ème. Cela dit tampis, j'ai revus le principe du pointeur ça m'a bien raffraichie les idées (des notions ou je commençais à avoir des doutes puisque plus trop pratiqué) et je sais qu'il faudra que je fasse gaf avec qt à chaque pointeur passé car lui le désalouera tout seul à la suppression...


Message édité par burn2 le 09-04-2009 à 09:16:55

---------------
"C'est vrai qu'un type aussi pénible de jour on serait en droit d'espérer qu'il fasse un break de nuit mais bon …"
Reply

Marsh Posté le 09-04-2009 à 12:53:07    

fais gaffe, pas sur que ca soit le cas pour tout les objets QT. La doc *doit* te el dire si oui ou non il y a ownership transfer

Reply

Marsh Posté le 09-04-2009 à 13:56:10    

Ouep je vérifierais. Mais bon j'essayais de comprendre comment ça pouvait passer deux fois d'affiler sans planter et planter la 3ème, et là je pense que le mystère reste entier. :D
 
Par contre je te conseille de tester mon while, car je peux t'assurer que ça remplis trés trés vite la mémoire. :D (pareil que les forks ou là par contre on peut aussi écrouler l'os :D)


---------------
"C'est vrai qu'un type aussi pénible de jour on serait en droit d'espérer qu'il fasse un break de nuit mais bon …"
Reply

Marsh Posté le 09-04-2009 à 14:24:45    

pour le while je sais merci, c'ets ce que je disasi au debut [:dawa]

Reply

Marsh Posté le 09-04-2009 à 16:08:41    

Joel F a écrit :

pour le while je sais merci, c'ets ce que je disasi au debut [:dawa]


Tes propos sont contradictoires alors:

Joel F a écrit :

je pense que non. Si t'arrive à voir l'effet d'une allocation de 4 octets dans ton moniteur de ram t'es super fort meme comme ça.
 
Alloue en boucle 1Mo et on en reparle



---------------
"C'est vrai qu'un type aussi pénible de jour on serait en droit d'espérer qu'il fasse un break de nuit mais bon …"
Reply

Marsh Posté le 09-04-2009 à 17:09:28    

sauf que la on se comprenait pas : je pensais que tu disais le contraire de ce que je disais sauf que tu disais l'inverse

Reply

Marsh Posté le 09-04-2009 à 17:40:03    

Je pense qu'on n'est pas sur la bonne onde, ceci explicant qu'on pense comprendre le contaire de l'autre. :D Mais bon ce qui importe c'est qu'on se comprenne au final. :D
Bon en tout cas merci de votre aides. Même si je ne saurais jamais pourquoi ça déconner toujours à la 3ème fois...


Message édité par burn2 le 09-04-2009 à 17:40:39

---------------
"C'est vrai qu'un type aussi pénible de jour on serait en droit d'espérer qu'il fasse un break de nuit mais bon …"
Reply

Marsh Posté le 10-04-2009 à 12:40:21    

Joel F a écrit :

 je pensais que tu disais le contraire de ce que je disais sauf que tu disais l'inverse


c bon ça

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

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