Je me suis récemment mis à QT pour tenter de faire un petit prog
Vient le moment de l'allocation dynamique.
Je veux créer un tableau d'instances de classes (je sais pas si les termes sont exactes, reprennez moi si ce n'est pas correct).
La class en question se nomme Unit.
Je suis en C++, je pense naturellement à new[] et delete[].
Seulement, je constate un ralentissement à la libération avec delete[]...
Un bout de code sera plus clair :
Unit* attUnit = NULL;
attUnit = (Unit*)malloc(sum * sizeof(Unit)); //tout le bazar de je vous zappe free(attUnit);
est TRES lent. J'ai "chronométré" l'exécution de ce bout de code pour voir ou ca n'allait pas, et les secondes perdues le sont à l'appel de delete[], alors que free est immédiat!
D'où ma question simple : pourquoi?
Merci pour vos réponses
si je ne raconte pas de bêtise, free se contente de libérer la mémoire, tandis que delete appelle les destructeurs des objets à libérer puis libère la mémoire.
Si tes destructeurs contiennent beaucoup d'instructions lentes, alors ça peut venir de là.
Utilise delete[] et puis c'est tout ! Nan mais c'est quoi ces idées de faire un remix entre langages, ce ne sont PAS les mêmes ! Toute tentative de "bidouillage" affreux aura des conséquences !
Ca me semble pas trop lent
Il me semblait aussi que delete[] appelait les destructeurs, mais au vu des miens, j'ai de suite rejeté cette hypothèse.
Merci quand même!
Si quelqu'un a une autre idée...
Citation : remram44
Utilise delete[] et puis c'est tout ! Nan mais c'est quoi ces idées de faire un remix entre langages, ce ne sont PAS les mêmes ! Toute tentative de "bidouillage" affreux aura des conséquences !
Sans problèmes avec delete[], je l'aurai utilisé. Mais ayant eu mon problème, j'en ai cherché la cause et ai du, c'est vrai, "bidouiller". Si on m'explique pourquoi delete[] me ralentit mon prog, je l'utilise!
lol ... je te rapelle que quand tu compile tu include plein de classe que tu immagine pas.
Comme tout celle d'I/O et elles aussi doivent etre detruite si necessair
De plus comme deja dit melange ce n'est pas bon...
Et si tu voit telment de difference... et bien ce que tu a couille grave ^^"
Merci, ca je sais...
Mais dans ce cas précis, j'ai les mêmes includes, et j'ai "couille grave" lorsque j'utilise delete[]. Je voudrais juste comprendre pourquoi?
Je veux pas faire de mélanges, je veux utiliser delete[], ici j'ai utilisé free pour comparer, c'est tout!
Arrêtez de me dire de pas mélanger, j'aurais pu balancer "j'utilise delete[] et c'est lent" -_-
Ca t'a été expliqué plus haut : delete[] appelle les destructeurs, c'est la seule différence à ma connaissance. Si les destructeurs sont lents (surtout dans un tableau) ça s'explique facilement.
Après, le destructeur de TA classe est peut-être court, mais si tu utilises d'autres objets dans ta classe (si ça se trouve des tableaux de string ou d'autres objets), il y aura autant d'appels de destructeurs qui EUX font quelque chose !
Ouf, une réponse claire
Seulement, ma classe est sensée faire des claculs... je n'ai que des double en gros...
Bon je vois ca demain matin, j'ai la flemme de m'y replonger là, mais je vais tout commenter dans ma class et voir la différence.
Rassures moi, tu utilises des options d'optimisation du compilateur ? S'il appelle réellement le destructeur à chaque fois c'est sûr que ça va ramer...
mmm tu pourrait poster le code pour voir si y a pas une librairie que tu utilise ou un autre truc qui est effectivement lent, mais ca me semble quand meme etrange que tu puisse apercevoire la lenteure (apart la compilation plus longue)
* Comment tu mesures le temps que prend ton delete ?
* A tout hasard : ne définis pas de destructeur pour un classe où son destructeur ne fait rien. Celui généré par défaut devrait suffir d'après le bout de code que tu nous as montré.
* Pas de fonctions virtuelles ? (j'essais de comprendre pourquoi le destructeur aurait un impact)
* GCC sous windows ? Ses ports ne sont pas toujours réputés pour produire des exécutables super rapides.
NB: je m'etais amusé à faire des mesures de perf pour des allocations/désallocations sur solaris pour des tableaux d'octets. Je n'avais pas noté de différence flagrante entre les new/delete et les *alloc/free
PS: si tes allocations ont lieu dans une boucle, tu as pas mal à gagner en faisant des resize() sur des vecteurs.
PPS: les *alloc sont strictement incompatibles avec des objets -- sauf feinte de construction/destruction placées comme les vecteurs les réalisent.
Par l'exemple, j'utilise ici le timer haute résolution de Windows pour obtenir un chonométrage très précis. La résolution de ce timer dépend directement de la vitesse du processeur. Pour l'échantillonner, j'appelle la fonction QueryPerformanceFrequency qui me retourne le nombre de top par seconde. Ensuite j'appelle QueryPerformanceCounter pour obtenir le nombre de top depuis le démarrage de la machine, par différence entre deux appels successif je peux mesurer un temps très précis.
Moyennes:
free: 25 soit 0.00698413 ms
delete[]: 10746 soit 3.00206 ms
L'explication du résultat: Le delete est intelligent, il analyse l'objet, dans le premier cas il n'y a pas de destructeur et pas d'objets utilisant un allocateur, il libère directement la mémoire, il va donc à la même vitesse que le free. Dans le second cas il y a un destructeur qui ne fait rien, mais il est quand même obligé de l'appeler (il n'y a pas d'optimisation, sinon il le supprime probablement), il perd donc du temps sur les appels du destructeur. Dans le troisème cas chaque appel du destructeur lui fait perdre entre 1 et 2 ms. En remplaçant le tableau par un vecteur, j'introduis une obligation pour le destructeur scalaire de détruire tous les vecteurs que j'ai créé donc cela prend plus de temps. Ce que l'on peut retenir c'est que mettre un destructeur qui ne fait rien est inutile, et que c'est même contre-productif.
Maintenant dans mon code je vais initialiser mes vecteurs avec la boucle suivante placée entre l'allocation et la libération
Et là c'est la catastrophe car le malloc a alloué la mémoire sans appeler les constructeurs, mes vecteurs ne sont donc pas initialisés. Et donc:
Microsoft Visual Studio C Runtime Library has detected a fatal error in cpp_console.exe (*)
Conclusion: Ne jamais utiliser malloc et free en C++, comme le montre la première série, on ne gagne rien sur les types simple et on prend des risques sur les classes.
(*) Pour obtenir ce message j'ai du compiler en release, car il y a un assert qui débouche sur un breakpoint en débug.
Par l'exemple, j'utilise ici le timer haute résolution de Windows pour obtenir un chonométrage très précis. La résolution de ce timer dépend directement de la vitesse du processeur. Pour l'échantillonner, j'appelle la fonction QueryPerformanceFrequency qui me retourne le nombre de top par seconde. Ensuite j'appelle QueryPerformanceCounter pour obtenir le nombre de top depuis le démarrage de la machine, par différence entre deux appels successif je peux mesurer un temps très précis.
<...>
Magnifique. Ca, c'est une réponse intelligente.
J'espère qu'à l'occasion, les forums (et tutoriels) C et C++ seront enfin séparés afin qu'on en finisse avec les mélanges entre ces deux langages qui n'ont rien à voir... C'est comme ça sur tous les forums sérieux Usenet ou web. Pourquoi serait-ce différent ici ? Esprit rebelle ?
Maintenant je vire les destructeurs et je remplace le tableau par un vecteur que je mets en public pour la suite
A partir du moment où le type n'est plus un POD, tu n'as plus le droit d'utiliser les *alloc() -- enfin, tu peux le faire, mais ça plantera.
Citation : int21h
Ce que l'on peut retenir c'est que mettre un destructeur qui ne fait rien est inutile, et que c'est même contre-productif.
Je suppose qu'un compilo intelligent aurait pû l'ignorer s'il avait été inliné comme une fonction vide. Avec définition séparée, il aurait fallu que le linker se rende compte que la fonction était vide pour faire sauter l'appel. Ce qui me parait un peu compliqué comme optimisation.
Citation : int21h
Conclusion: Ne jamais utiliser malloc et free en C++, comme le montre la première série, on ne gagne rien sur les types simple et on prend des risques sur les classes.
Ce n'est pas une histoire de prendre des risques, cela ne marchera juste pas avec les types non-POD vu qu'une étape nécessaire aura été oubliée.
Le premier appel à resize(0) n'est nécessaire que s'il y a besoin de réinitialiser par default construction tous les éléments. Quand on a une sémantique devaleur, une simple affectation écrasante suffit.
Et suivant les allocateurs, cette feinte n'apporte pas grand chose -- surtout si on réalise les 2 resize.
NB: c'est l'équivalent du realloc aux détails que:
- cela marche aussi avec les types non-POD
- cela lêve une exception au lieu de renvoyer null si le redimensionnement est impossible
Merci à tous pour ces réponses, qui ont du en plus vous prendre pas mal de temps.
J'ai trouvé d'où vient mon problème...
Comme je débute en C++, j'ai fait hériter ma class Unit d'une autre class beaucoup plus complexe... en passant cette class en amie, plus de problème.
Merci pour vos réponses encore une fois, je n'aurais pas trouvé sans vos indications!
Merci à tous pour ces réponses, qui ont du en plus vous prendre pas mal de temps.
J'ai trouvé d'où vient mon problème...
Comme je débute en C++, j'ai fait hériter ma class Unit d'une autre class beaucoup plus complexe... en passant cette class en amie, plus de problème.
Merci pour vos réponses encore une fois, je n'aurais pas trouvé sans vos indications!
Petite precision, frien de heritage sont 2 chose completement differentes... ^^"
Donc faut bien l'utiliser, et sourtout utiliser le bon dans le bon cas
Mais ca ce une question de POO et pas specialment de C++
Je sais bien!
Et dans mon cas, faire hériter était inutile.
Comme je l'ai précisé, je débute en C++. Je faisais du C avant, et je débute donc aussi en POO!
[C++] new[]/delete[] vs malloc/free...
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
If you'd like to join us, read "How do we work at OpenClassrooms"! :)