Mais même s'ils le font, ils peuvent être moins performants dans ce cas. Windows notamment est optimisé pour le cas où les ressources sont libérées correctement; la libération "par l'OS" n'est pas forcément rapide.
Mais même s'ils le font, ils peuvent être moins performants dans ce cas. Windows notamment est optimisé pour le cas où les ressources sont libérées correctement; la libération "par l'OS" n'est pas forcément rapide.
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
Il s'agit ici de fenêtres qui ne sont pas détruites par une application avant de sortir. Le gestionnaire de fenêtres (Windows en l'occurence) ne se termine pas et doit donc libérer sa propre mémoire. Ca n'a pas vraiment de lien avec la question. Avec Windows comme avec tous les OS qui se respectent, embarqués ou pas, la mémoire d'un processus terminé est libérée.
Non seulement cette libération par l'OS est rapide, mais elle est en fait plus rapide que lorsque c'est le programme qui l'effectue avant de se terminer.la libération "par l'OS" n'est pas forcément rapide.
En effet, un processus qui libère la mémoire qu'il a alloué doit faire un appel à free pour chaque pointeur. Chaque appel va nécessiter des contrôles et des écritures, ce qui peut être non négligeable si on a alloué des milliers/millions de blocs mémoire.
En revanche, qu'elle ait été libérée par programme ou pas, l'OS va libérer "d'un coup" la totalité de la mémoire virtuelle mappée en RAM ou dans le swap sans se poser de questions.
Edit: Bien sûr, ne pas prendre ma réponse pour un encouragement à ne pas libérer la mémoire allouée lorsqu'elle n'est plus nécessaire !
ɹǝsn *sıɹɐlos*
Pour reprendre ce que j'ai dis, effectivement, ne pas libérer la mémoire et compter sur l'OS pour la libérer c'est pas top, clairement.
Ensuite, un OS doit OBLIGATOIREMENT libérer la mémoire à la fin d'un programme, peu importe ce qu'il se passe.
Prenons un exemple:
J'ai mon ptit OS sur un periph embarqué avec 56k de ram.
Je bidouille un peu avec mon prog, y consomme 22k de ram, jcommence à être un peu juste et la paf, un tit segfault pour x raison.
Imaginez si à ce moment la l'OS ne libère pas la mémoire, beh du coup on peu plus rien faire ......
Donc oui c'est pas une bonne pratique de ne pas libérer la mémoire au fur et a mesure qu'on l'utilise.
Mais non, c'est pas un drame si on ne le fait pas pour des programmes One-shot (chose que la plupart ont oubliés de lire apparemment .
Dans une grosse société dont je ne dirais pas le nom, où je bosse, on fonctionne exclusivement avec des prog one-shot qui vont allouer pas mal de petit bloc de mémoire qui seront utiles tout le long du traitement.
Et dans des soucis d'optimisation, on ne libère pas la mémoire, on laisse l'OS s'en charger car il sera beaucoup plus rapide que nous pour retrouver les plage mémoires allouées.
Pas de solution, pas de probleme
Une réponse utile (ou +1) ->
Une réponse inutile ou pas d'accord -> et expliquer pourquoi
Une réponse à votre question
Mon problème lors du post, c'est la 1. D'où le fait que je crée un nouveau topic : c'est redondant, et on peut oublier des pointeurs avec de la mémoire allouait.
Après c'est vrai j'ai pensé à la deuxième, mais c'est lourd au niveau de la lecture du code.
Moi je suis pour la 3e. C'est la même chose que la deux, mais en plus clair. Car si on voit ça en bas niveau, il y a rien de mal à utiliser goto. (?) Donc j'utilise une variable pour le code retour de mon programme, et je l'utilise au return au final.
Normalement il n'y a pas de mal si j'utilise dans le main plusieurs fois goto clean?
C'est toujours un plaisir de poser des questions sur ce site (forum), c'est toujours très instructif. Merci à tous.
Et je suis sur un très bon OS, je lui fais confiance.
"Les spécialistes commencent par n'apprendre que ce qu'ils aiment et finissent par n'aimer que ce qu'ils ont appris." - Gilbert Cesbron
"Si nous avons chacun un objet et que nous les echangeons, nous avons chacun un objet. Si nous avons chacun une idée et que nous les échangeons, nous avons chacun deux idées." - Proverbe Chinois.
ouh! Je profite du topic, en relisant les commentaires, je vois (et c'est pas la première fois bien sûr) que pour tester si un pointeur est NULL, c'est écrit :
Mais moi je fais toujours
Code c : Sélectionner tout - Visualiser dans une fenêtre à part if (p == NULL) ...
C'est grave docteur?
Code c : Sélectionner tout - Visualiser dans une fenêtre à part if (!p) ...
"Les spécialistes commencent par n'apprendre que ce qu'ils aiment et finissent par n'aimer que ce qu'ils ont appris." - Gilbert Cesbron
"Si nous avons chacun un objet et que nous les echangeons, nous avons chacun un objet. Si nous avons chacun une idée et que nous les échangeons, nous avons chacun deux idées." - Proverbe Chinois.
Ce n'est pas en soi un problème (c'est parfaitement légal en C et C++, et ça a le même effet) mais c'est légèrement moins lisible (donc, moins maintenable).
Si ta variable s'appelle (ou commence par) p, ça ne gène pas vraiment la lecture.
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
oui je ne voyais pas les choses comme ça...
"Les spécialistes commencent par n'apprendre que ce qu'ils aiment et finissent par n'aimer que ce qu'ils ont appris." - Gilbert Cesbron
"Si nous avons chacun un objet et que nous les echangeons, nous avons chacun un objet. Si nous avons chacun une idée et que nous les échangeons, nous avons chacun deux idées." - Proverbe Chinois.
A vrai dire il me semble avoir lu un post disant qu'en c++ il valait mieux ecrire :
plutot que :
Code : Sélectionner tout - Visualiser dans une fenêtre à part if (!p)
Je cherche le topic et j'editerai ce post si j'arrive a le retrouver.
Code : Sélectionner tout - Visualiser dans une fenêtre à part if (p == NULL)
Je pense que c'est une question de pratique et / ou d'habitude a ce niveau la. Pour moi les deux comparaisons reviennent au meme et ne genent en rien la visibilite du code.Envoyé par Médinoc
Ben oui. La prog c'est aussi un peu de travail...
Il n'y a rien de mal à utiliser goto à bon escient. Sa mauvaise image vient du basic où il n'y avait que cette instruction qui donnait des programmes difficilements lisibles. Warnier a tenté une méthodologie basée sur cette instruction qui est ce qu'elle est mais bon, maintenant qu'il y a des whiles() et des for()...
Tu peux utiliser errno qui est là pour ça. Sauf si tu as peur d'une collision (elle est impactée à chaque appel system qui se passe mal)...
J'espère que l'étiquette "clean" se trouve elle-aussi dans le main. Alors pas de souci si tu gardes à l'esprit que ce doit être une instruction exceptionnelle réservée à la gestion des erreurs. Maintenant moi j'ai une maxime personnelle pour ce genre de question : un bon programmeur respecte les règles ; un programmeur brillant les transgresse parfois...
Bah, est-ce que tu as peur de dépasser ton quota ? Sois large, aéré et explicite dans ton code. Au final l'optimiseur donnera le même exécutable mais quel plaisir de se relire facilement. et puis c'est tellement facile de se tromper et d'écrire if (p) au lieu de if (!p) et inversement alors que quand on écrit l'égalité explicite...
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
Bah j'y pensais à errno, mais il y aura des erreurs qui viendront pas d'une histoire de système (comme erreur d'arguments, oublie d'argument, ...).
Oui le clean se trouve tout à la fin du main, et j'ai retiré tous les exit() venant du main ou ailleurs, et je l'ai remplacé par goto clean;, avec bien sûr le changement de valeur pour la variable de retour.
"Les spécialistes commencent par n'apprendre que ce qu'ils aiment et finissent par n'aimer que ce qu'ils ont appris." - Gilbert Cesbron
"Si nous avons chacun un objet et que nous les echangeons, nous avons chacun un objet. Si nous avons chacun une idée et que nous les échangeons, nous avons chacun deux idées." - Proverbe Chinois.
Bonjour,
Pour if(!p) vs if(p == NULL), j'ai deux arguments en faveurs de if(!p) en C++ :
- c'est plus court à écrire ;
- on respecte le principe "d'encapsulation" pour les pointeurs "intelligents" :
---> On a pas à savoir l'adresse du pointeur ni s'il vaut NULL (nullptr en C++11) ou non. On a juste besoin de savoir s'il est valide ou non (ce qui n'est pas tout à fait la même chose ).
Ensuite, pour le malloc, attention, sous Linux, par défaut, le malloc ne renverra jamais NULL. En effet l'allocation n'est réellement effectuée qu'à la première utilisation de l'espace alloué.
Après, pour la libération de la mémoire, plutôt que de faire :
On peut aussi faire :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 int fonction() { char *buf1=NULL; char *buf2=NULL; char *buf3=NULL; buf1=malloc(...) buf2=malloc(...) buf3=malloc(...) if (buf1 == NULL || buf2 == NULL || buf3 == NULL) goto clean; .... // travail // Nettoyage clean: free(buf1); free(buf2); free(buf3); }
Ce qui pourrait être très pratique si tu as beaucoup d'allocations à faire.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 #define Malloc(Z) ( alloc_it < alloc_max ? ( alloc[alloc_it++] = malloc(Z) ) : NULL ) #define debutAlloc(SIZE) unsigned int alloc_it = 0; unsigned int alloc_max ; void * alloc[alloc_max = (SIZE)] = {NULL} #define finAlloc() do{ for(int i= 0; i < XX ; ++i) \ free(alloc[XX]); \ while(0) void foo(void) { debutAlloc(50); int * toto = (int *)Malloc(sizeof(int) ); if( ! toto ) { finAlloc(); puts(":cry:"); return; } // do some stuff finAlloc(); }
Les #define pourront être utile si tu veux faire la même chose dans plusieurs fonctions (ou pour frimer )
Non. Il est impacté par chaque appel système échoué (fopen, malloc, pipe, etc etc etc). Mais c'est conventionnel (chaque fonction a été codée pour le mettre à jour quand elle échoue).
En revanche, un oubli d'arguments n'est pas un pb système mais un pb humain donc il n'est pas impacté.
Ah j'aime pas quand je lis ce genre de truc car je me sens dépassé et ça m'énerve. Bref en quoi "l'encapsulation" fonctionne avec if(!p) et ne fonctionne pas avec if (p == NULL) ? Et quelle différence entre "pointeur invalide" et "pointeur égal à NULL" ? malloc ne renvoie-t-elle pas NULL quand elle échoue ??? Parce que je ne teste pas "pointeur invalide" mais "pointeur égal à la valeur conventionnellement renvoyée par malloc en cas d'échec" ce qui n'est pas tout à fait la même chose dans la notion (même si c'est la même chose dans l'écriture)...
Et que renvoie-t-elle si elle échoue ??? Parce que le man, lui, parle explicitement de NULL...
Ok, c'est réglé je suis complètement dépassé...
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
Je parle C++ là.
p == NULL risque de ne pas marcher car l'opérateur de comparaison et le constructeur peuvent ne pas prendre un pointeur en paramètre (ce qui serait logique, l'utilisateur n'a pas à récupérer l'adresse stockée).
Après, un pointeur "NULL" sera invalide, mais l'inverse ne sera pas forcément vraie selon l'implémentation.
malloc ne renvoie-t-elle pas NULL quand elle échoue ???If size is 0, then
malloc() returns either NULL, or a unique pointer value that can later
be successfully passed to free().Il ne me semble pas que malloc puisse échouer pour une autre raison que :By default, Linux follows an optimistic memory allocation strategy.
This means that when malloc() returns non-NULL there is no guarantee
that the memory really is available.
- la taille passée en paramètre (autant dire que ça ne devrait jamais planter );
- un problème d'allocation (plus que rare, sauf en cas de fuite mémoire et vérifier le type de retour ne marchera pas sous Linux);
Donc on peut se permettre de ne pas tester le code de retour de malloc dans certains programmes.
Je pense que c'est pas le meilleur topic pour débattre if(!p) vs if(p == NULL) , alors pour moi un code doit être explicite et if(!p) ne l'est pas.
Après évidement que ça marche mais du code moche marche très bien en C
Le define NULL n'a pas été créer pour faire jolie...
@Neckara
Ton code est très moche , et n'est vraiment pas un bon exemple , surtout que meme si c'est possible de mettre a peu prés tout sur le define (même des déclaration et du code) , je ne le conseille pas je rappelle que tu fais ça :
Un define que tu pourra pas utiliser 2 fois (tu vas pas pouvoir faire 2 fois la déclaration de alloc_it).
Code : Sélectionner tout - Visualiser dans une fenêtre à part #define debutAlloc(SIZE) unsigned int alloc_it = 0; unsigned int alloc_max ; void * alloc[alloc_max = (SIZE)] = {NULL}
Pour un petit code ça peut déjà limite alors sur du gros code si tu code comme ça , je t'envoie boulet vu que ça obligera au programmeur de regarde chaque fois le define (pas simple a lire deja) pour savoir ce que fait ton code.
Pour être un peu méchant j'ai impression de voir du code débutant inutilement complexe et peu maintenable.
Pour moi, c'est même plus qu'explicite :
- On teste si le pointeur est valide (bon/ok) ou non (pas bon/false) ;
Je trouve que c'est plus intuitif.
Il suffit de connaître un minimum le langage pour savoir que :
- 0 -> false ;
- NULL -> false ;
Et puis pour reprendre ton argument, ce n'est pas pour rien qu'en C++, on a ajouté des surcharges pour pouvoir faire :
Pour moi, NULL sert surtout à éviter de faire :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 if( file); if( ! file );
Code : Sélectionner tout - Visualiser dans une fenêtre à part void * ptr = (void *)0;
Le but d'un tel code est d'être mis en début et en fin de fonction.@Neckara
Ton code est très moche , et n'est vraiment pas un bon exemple , surtout que meme si c'est possible de mettre a peu prés tout sur le define (même des déclaration et du code) , je ne le conseille pas je rappelle que tu fais ça :
Un define que tu pourra pas utiliser 2 fois (tu vas pas pouvoir faire 2 fois la déclaration de alloc_it).
Code : Sélectionner tout - Visualiser dans une fenêtre à part #define debutAlloc(SIZE) unsigned int alloc_it = 0; unsigned int alloc_max ; void * alloc[alloc_max = (SIZE)] = {NULL}
Il n'est donc pas fait pour être présent deux fois dans une fonction, après, c'est une chose à documenter etc.
Ensuite, je ne donne qu'un exemple, on peut très bien ajouter un deuxième argument pour donner un nom de variable unique et donc passer cette limitation.
Une bonne solution serait d'utiliser des listes chaînée mais il faudrait allouer les maillons .
Non, il n'a pas à le savoir.Pour un petit code ça peut déjà limite alors sur du gros code si tu code comme ça , je t'envoie boulet vu que ça obligera au programmeur de regarde chaque fois le define (pas simple a lire deja) pour savoir ce que fait ton code.
Il sait juste qu'il "réserve" X allocations.
Il fait X allocation puis il "libère" en fin de fonction et c'est tout.
Il copie/colle en début et en fin de fonction, il utilise Malloc() au lieu de malloc(), j'ai pas plus simple.
Après, l'avantage des #define, c'est que ce genre de code est censé être utilisé de partout. Il est inconcevable de copier coller plusieurs lignes dans toutes les fonctions. Ceci sera bien plus maintenable que de corriger 5/6 lignes par fichiers .
Ensuite, ce n'est pas en 5 minutes à 20h après une longue journée de cours que je vais pondre un code "super propre" comme ça sur un coup de tête
Je ne sais pas si c'est possible de faire ça par contre :
Je pense qu'on pourrait faire des choses marrantes avec
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 #define Malloc ... #define ManagedFunction(PROTOTYPE, CORPS, ALLOC_MAX) \ PROTOTYPE \ { \ début; \ CORPS \ fin; \ }
On pourrait même faire une unique allocation mémoire au début puis on gère soit-même sa mémoire (juste pour s'amuser un peu ).
EDIT : Oui ça marche \o/
On va pouvoir s'amuser un peu
Pourquoi choisir des macros plutôt que des fonctions inline ?
Mais euh... s'il faut que je réfléchisse avant de poster aussi
Le seul "inconvénient" c'est qu'il faudra déclarer soit-même les variables donc oui, je pense que les fonctions inlines seront plus appropriées.
Pour mon dernier code, le but serait de pouvoir faire un peu comme le Java fait :
Donc là les macros seront obligatoires je pense.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 synchronisez void foo(void) { }
Pas souvent, mais pas jamais. malloc renverra NULL sous linux si l'espace adressable est épuisé, donc pas plus de 4 Go (et même 3 Go en général car le noyau se réserve 1 Go) pour un processus en 32 bit. Pour un processus en 64 bit, la configuration par défaut place aussi une limite "raisonnable" sans plus de détail. Les OS plus conformes aux standards n'autorisent pas de malloc si la mémoire disponible (incluant une partie de la RAM plus la taille cumulées des zones de swap éventuelles) ne permet pas de stocker les pages réservées par la totalité des processus en cours.
Ce mode de fonctionnement n'est pas spécifique à Linux. Tous les OS modernes qui implémentent la mémoire virtuelle et la pagination à la demande n'allouent de la mémoire réelle (RAM ou swap) qu'au fur et à mesure de l'utilisation de chaque page mémoire utile. Les pages allouées (on devrait dire réservées) mais jamais utilisées n'ont pas de contenu et ne sont donc stockées nulle part.En effet l'allocation n'est réellement effectuée qu'à la première utilisation de l'espace alloué.
ɹǝsn *sıɹɐlos*
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager