web-dev-qa-db-fra.com

C ++: supprimer vs gratuit et performances

  1. Considérer:

    char *p=NULL;
    free(p) // or
    delete p;
    

    Que se passera-t-il si j'utilise free et delete sur p?

  2. Si un programme prend beaucoup de temps à exécuter, disons 10 minutes, existe-t-il un moyen de réduire son temps d'exécution à 5 minutes?

26
user41522

Quelques notes de performance sur new/delete et malloc/free:

malloc et free ne pas faire appeler le constructeur et le déconstructeur, respectivement. Cela signifie que vos classes ne seront pas automatiquement initialisées ou désinitialisées, ce qui pourrait être mauvais (par exemple, des pointeurs non initialisés)! Cela n'a pas d'importance pour les types de données POD comme char et double, car ils n'ont pas vraiment de ctor.

new et delete do appelez le constructeur et le déconstructeur. Cela signifie que vos instances de classe sont automatiquement initialisées et désinitialisées. Cependant, normalement, il y a un impact sur les performances (par rapport à une allocation simple), mais c'est pour le mieux.

Je suggère de rester cohérent avec l'utilisation de new/malloc, sauf si vous avez une raison (par exemple, realloc). De cette façon, vous avez moins de dépendances, ce qui réduit la taille de votre code et le temps de chargement (seulement par un smidgin, cependant). De plus, vous ne gâcherez pas en libérant quelque chose alloué avec new ou en supprimant quelque chose alloué avec malloc. (Cela entraînera très probablement un crash!)

61
strager

Réponse 1: free(p) et delete p fonctionne très bien avec un pointeur NULL.

Réponse 2: Impossible de répondre sans voir les parties lentes du code. Vous devez profiler le code! Si vous utilisez Linux, je suggère d'utiliser Callgrind (partie de Valgrind ) pour savoir quelles parties de l'exécution prennent le plus de temps.

13
activout.se

Première question: rien ne se passera.

D'après le projet actuel d'ISO/CEI 14882 (ou: C++):

20.8.15 Bibliothèque C [c.malloc]

Le contenu [de <cstdlib>, C'est-à-dire: où free habite,] est le même que la bibliothèque C standard [(voir les références intro pour cela)] en-tête <stdlib.h>, avec les modifications suivantes: [rien qui affecte cette réponse].

Ainsi, d'après ISO/IEC 9899: 1999 (ou: C):

7.20.3.2 La fonction free

Si [le] ptr [paramètre] est un pointeur nul, aucune action ne se produit .

A partir du standard C++ à nouveau, pour plus d'informations sur delete cette fois:

3.7.4.2 Fonctions de désallocation [basic.stc.dynamic.deallocation]

La valeur du premier argument fourni à une fonction de désallocation peut être une valeur de pointeur nulle; dans l'affirmative, et si la fonction de désallocation est celle fournie dans la bibliothèque standard, l'appel n'a aucun effet .

Voir également:

10
cic

Rien ne se passera si vous appelez free avec un paramètre NULL ou supprimez avec un opérande NULL. Les deux sont définis pour accepter NULL et n'effectuer aucune action.

Il y a un certain nombre de choses que vous pouvez changer dans le code C++ qui peuvent affecter sa vitesse d'exécution. Les plus utiles (dans l'ordre approximatif) sont souvent:

  • Utilisez de bons algorithmes. C'est un gros sujet, mais par exemple, j'ai récemment réduit de moitié le temps d'exécution d'un peu de code en utilisant un vecteur std :: au lieu d'une liste std ::, dans le cas où des éléments étaient ajoutés et supprimés uniquement à la fin .
  • Évitez de répéter de longs calculs.
  • Évitez de créer et de copier des objets inutilement (mais tout ce qui se produit moins de 10 millions de fois par minute ne fera aucune différence significative, sauf si vous manipulez quelque chose vraiment gros, comme un vecteur de 10 millions d'éléments) .
  • Compilez avec optimisation.
  • Marquez les fonctions couramment utilisées (encore une fois, tout ce qui est appelé plus de 100 millions de fois dans votre durée d'exécution de 10 minutes), comme en ligne.

Cela dit, divideandconquer a absolument raison - vous ne pouvez pas accélérer efficacement votre programme à moins de savoir ce qu'il passe son temps à faire. Parfois, cela peut être deviné correctement lorsque vous savez comment fonctionne le code, d'autres fois, c'est très surprenant. Il est donc préférable de profiler. Même si vous ne pouvez pas profiler le code pour voir exactement où le temps est passé, si vous mesurez l'effet de vos modifications, vous pouvez souvent le découvrir éventuellement.

4
Steve Jessop

Comme d'autres l'ont souligné, la suppression (ou la libération) d'un pointeur NULL ne fera rien. Cependant, si vous avez alloué de la mémoire, l'utilisation de free () ou delete dépend de la méthode que vous avez utilisée pour les allouer. Par exemple, si vous avez utilisé malloc () pour allouer de la mémoire, vous devez libérer () et si vous avez utilisé new pour allouer, vous devez utiliser delete. Cependant, veillez à ne pas mélanger les allocations de mémoire. Utilisez une seule façon pour les allouer et les désallouer.

Pour la deuxième question, il sera très difficile de généraliser sans voir le code réel. Elle doit être prise au cas par cas.

2
Naveen

Sur la question 2:
Les réponses précédentes sont excellentes. Mais je voulais juste ajouter quelque chose sur la pré-optimisation. En supposant un programme de complexité modérée, la règle 90/10 s'applique généralement - c'est-à-dire que 90% du temps d'exécution est consacré à 10% du code. Le code "optimisé" est souvent plus difficile à lire et à maintenir. Donc, résolvez toujours les problèmes d'abord, puis voyez où se trouvent les goulots d'étranglement (le profilage est un bon outil).

2
E Dominique

Bonnes réponses à tous.

Sur le problème des performances, this fournit une méthode que la plupart ne peuvent pas imaginer fonctionnera, mais certains le savent, étonnamment bien.

La règle 90/10 est vraie. D'après mon expérience, il y a généralement plusieurs points chauds, et ils se trouvent généralement au milieu de la pile d'appels. Ils sont souvent causés par l'utilisation de structures de données trop générales, mais vous ne devez jamais réparer quelque chose à moins que vous n'ayez prouvé qu'il s'agit réellement d'un problème. Les problèmes de performances sont incroyablement imprévisibles.

La résolution d'un problème de performance unique peut ne pas vous donner l'accélération dont vous avez besoin, mais chacun de ceux que vous corrigez fait que les autres prennent plus de temps, donc ils sont plus faciles à trouver. Les accélérations se combinent de manière composée, vous pouvez donc être surpris du résultat final.

Lorsque vous ne pouvez plus trouver de problèmes importants que vous pouvez résoudre, vous avez fait de votre mieux. Parfois, à ce stade, une refonte (comme l'utilisation de la génération de code) peut déclencher une nouvelle série d'accélérations.

1
Mike Dunlavey