Vous êtes sur la page 1sur 9

Centre Informatique pour les Lettres

et les Sciences Humaines


Apprendre C++ avec Qt : Leon 12
Allocation dynamique






1 - Notion de porte.................................................................................................................. 2
2 - Notion de dure de stockage................................................................................................ 2
3 - Variables locales statiques .................................................................................................. 3
Principe gnral...............................................................................................................3
Le cas des fonctions membre...........................................................................................4
Variables membre statiques vs. variables locales statiques d'une fonction membre .........5
4 - Allocation dynamique.......................................................................................................... 5
Rserver de la mmoire avec new.....................................................................................5
Initialiser une zone mmoire rserve avec new................................................................6
Librer la mmoire avec del et e ......................................................................................6
Les fuites de mmoire......................................................................................................8
A quoi sert rellement l'allocation dynamique ? ...............................................................8
5 - Bon, c'est gentil tout a, mais a fait dj 7 pages. Qu'est-ce que je dois vraiment en
retenir ?.............................................................................................................................. 9

Document du 22/08/05 - Retrouvez la version la plus rcente sur http://www.up.univ-mrs.fr/wcpp
C++ - Leon 12 Allocation dynamique 2/9
Les objets que nous avons manipuls jusqu' prsent sont des variables locales au bloc
l'intrieur duquel elles sont dfinies. Avant d'introduire la possibilit de crer des objets d'un
autre type, prenons quelques instants pour prciser deux notions qui vont s'avrer importantes
pour bien comprendre en quoi ces nouveaux objets diffrent de ceux que nous connaissons dj.
1 - Notion de porte
On appelle porte d'une variable (ou d'une fonction) la portion du programme dans laquelle il
est possible d'accder la variable (ou la fonction) en utilisant son nom.

Le terme anglais dsignant la porte est scope.

Il faut remarquer que le fait que le nom d'une variable ne permette pas d'accder celle-ci
n'implique pas ncessairement que la variable ait cess d'exister. Une simple homonymie entre
variables permet de crer une situation illustrant ce fait. Dans l'exemple suivant, nous avons
simplement deux blocs de code, dont l'un est inclus dans l'autre. Nous savons que, dans ce
cas, les variables locales du bloc externe sont disponibles l'intrieur du bloc interne.

Oui, nous le savons. Comment pourrait-on utiliser les structures de contrle (les f or , whi l e et
autres i f ), si les blocs dont ces structures contrlent l'excution ne pouvaient accder qu' leurs
propres variables locales ?

{ 1
i nt t est = 4; / / df i ni t i on d' une pr emi r e var i abl e nomme t est 2
{ 3
t est = 5; / / changement de l a val eur cont enue dans l a pr emi r e var i abl e 4
i nt t est = 3; / / df i ni t i on d' une seconde var i abl e nomme t est 5
/ / i l est devenu i mpossi bl e d' accder l a var i abl e qui cont i ent 5 6
}/ / l a var i abl e qui cont i ent 3 cesse d' exi st er i ci 7
/ / i l est nouveau possi bl e d' accder l a var i abl e qui cont i ent 5 8
} 9

Ce qui rend cette situation particulire, c'est que les blocs possdent tous les deux une variable
locale nomme t est . Une fois dfinie, la variable du bloc interne masque la variable
homonyme dfinie dans le bloc externe, ce qui signifie que celle-ci se retrouve hors de porte
(on ne peut plus y accder en utilisant son nom). Ds l'accolade marquant la fin du bloc
interne (7), la variable locale de celui-ci cesse d'exister. Le phnomne de masquage disparat
donc, et la variable locale du bloc externe redevient accessible. Elle a mme conserv son
contenu, ce qui prouve bien qu'elle n'a jamais cess d'exister.

Le fragment de code prsent ci-dessus n'est destin qu' mettre en vidence la diffrence entre
porte et existence. Il ne constitue certainement pas un exemple stylistique qu'il serait judicieux
de suivre. En effet, s'il est parfois lgitime de dfinir une variable qui en masque une autre, il
serait de trs mauvais got de le faire dans un bloc qui manipule galement la variable masque.
Si un mme nom peut ventuellement dsigner des choses diffrentes diffrents moments, il
est prfrable de conserver une correspondance entre "moments" et "blocs de code", faute de
quoi la lisibilit du programme risque d'tre compromise.
2 - Notion de dure de stockage
Lorsqu'on dit qu'une variable "cesse d'exister", cela signifie que la zone de mmoire dont l'tat
reprsentait le contenu de la variable cesse d'tre rserve cet usage. Toutes les variables
cessent videmment d'exister lorsque l'excution du programme s'achve, et nous savons aussi
que les variables locales cessent d'exister lorsque s'achve l'excution du bloc de code
l'intrieur duquel elles sont dfinies.

Lorsque la variable qui cesse d'exister est une instance d'une classe, ses variables membre
cessent galement d'exister (elles ne sont que des sous-variables de l'instance).

Le fait qu'une variable cesse d'exister n'a pas forcment pour consquence une modification
immdiate de l'tat de la zone de mmoire qui lui tait rserve, mais plus rien ne garantit que
cet tat ne variera que d'une faon cohrente avec la signification qu'avait la variable. Il devient
donc extrmement prilleux d'interprter cet tat comme s'il correspondait encore au contenu
de la variable, et le langage, trs logiquement, interdit alors d'utiliser le nom de la variable.
J-L Pris - 22/08/05
C++ - Leon 12 Allocation dynamique 3/9
Remarquons tout de suite que, si l'on accde la zone de mmoire qui correspondait la
variable en utilisant un pointeur contenant son adresse, le langage N'EST PAS en mesure de
proposer une scurit analogue celle offerte par l'interdiction de l'usage du nom de la
variable. Cette situation est illustre dans l'exemple suivant :

{ 1
i nt uneVar i abl e; 2
i nt *poi nt eur = & uneVar i abl e; 3
*poi nt eur = 5; / / OK, on r ange 5 dans uneVar i abl e, en f ai t 4
{ 5
i nt uneVar i abl eLocal e; 6
poi nt eur = & uneVar i abl eLocal e; 7
*poi nt eur = 5; / / OK, on r ange 5 dans uneVar i abl eLocal e, en f ai t 8
}/ / uneVar i abl eLocal e cesse d' exi st er ! 9
*poi nt eur = 5; / / DANGER : on modi f i e une zone de mmoi r e dont on i gnor e t out 10
} 11

Ce danger est insidieux, car il est fort possible que le programme ne prsente aucun symptme
immdiat. Tant que la zone de mmoire qui tait attribue uneVar i abl eLocal e n'est pas
affecte un autre usage, tout semble en effet se passer normalement. Le problme peut
n'apparatre que bien plus tard au cours du dveloppement du programme et, qui plus est, il
risque fort de se manifester par l'apparition de valeurs fantaisistes dans une variable qui n'a
aucun rapport avec la ligne de code qui contient l'erreur. Les erreurs de ce type sont donc trs
difficiles dtecter et il faut tout prix essayer d'viter de les commettre.

Lorsqu'une variable cesse d'exister, tous les pointeurs qui contiennent son adresse cessent
d'tre valides et constituent autant de menaces graves pour l'intgrit du programme.

En ralit, les vrais problmes n'apparaissent que dans des situations bien plus complexes que
celle illustre ci-dessus. Quoi qu'en disent certains esprits chagrins, tant que vous comprenez
rellement ce que vous faites, l'usage de pointeurs n'est pas plus dangereux que n'importe
quelle autre technique de programmation.

Et, si vous ne comprenez pas rellement ce que vous faites, toutes les techniques de
programmation s'avrent finalement trop dangereuses.
3 - Variables locales statiques
Une variable locale "ordinaire" cesse d'exister la fin de l'excution du bloc dans lequel elle est
dfinie. Sa dure de stockage correspond donc exactement sa porte : elle nat au moment de
l'excution de l'instruction qui la dfini, meurt la fin du bloc, et seules les instructions
figurant entre ces deux points peuvent y accder en utilisant son nom.

Si un objet portant un nom identique est dfini ailleurs, il ne s'agit du mme nom que d'un point
de vue purement orthographique. Du point de vue de C++, ces deux noms sont aussi diffrents
que s'ils n'avaient pas une seule lettre en commun.

Chaque fois qu'un bloc est excut, ses variables locales sont recres et, ventuellement, r-
initialises. Dans le cas d'une fonction, il arrive que cette caractristique des variables locales
ne permette pas d'obtenir l'effet recherch.
Principe gnral
Imaginons une fonction qui a, pour une raison quelconque, besoin de tenir compte du nombre
de fois o elle a dj t appele. Une variable locale ordinaire ne peut servir tenir ce compte,
puisque son contenu est perdu la fin de chacune des excutions de la fonction. D'un autre
ct, si cette fonction est appele partir de plusieurs parties diffrentes du programme, il
peut s'avrer assez complexe de lui passer, lors de chaque appel, l'adresse d'une mme variable
dans laquelle elle pourrait tenir jour le dnombrement des appels.

La difficult provient du fait que les diffrentes parties du programme n'ont pas forcment, elles-
mmes, la possibilit de toutes accder une mme variable. Cette approche aurait, en outre,
l'inconvnient de crer une variable dont la porte dpasserait largement la zone du programme
o elle est effectivement utile, qui est limite la fonction. Un tel dpassement est viter, car il
augmente le risque que la variable soit modifie par un programmeur n'ayant pas parfaitement
conscience de sa signification et de la faon dont elle doit tre manipule.
J-L Pris - 22/08/05
C++ - Leon 12 Allocation dynamique 4/9
Il existe un moyen simple pour rsoudre ce problme : crer des variables locales dont la dure
de stockage n'est pas limite l'excution de la fonction. Pour crer ce type de variables, il
suffit, lors de leur dfinition, de faire prcder leur type du mot st at i c.

Les variables locales st at i c naissent (et sont initialises) lors de la premire excution du bloc
o elles sont dfinies. Elles ont la porte habituelle mais ne meurent qu' la fin du programme.

Le fragment de code suivant dfinit une fonction dont les appels successifs produisent
progressivement la suite des nombres positifs impairs :

i nt gener at eur DI mpai r s( ) 1
{ 2
st at i c i nt i mpai r Sui vant = - 1; / / df i ni t i on et i ni t i al i sat i on 3
i mpai r Sui vant = i mpai r Sui vant + 2; 4
r et ur n i mpai r Sui vant ; 5
} 6

Remarquez qu'une telle fonction ne pourrait pas tre crite s'il n'existait pas un processus
d'initialisation distinct de celui de l'affectation. Remarquez galement que, l'usage, ce genre de
fonction peut rserver quelques surprises :

i nt n;
f or ( n=0 ; n < 5 ; ++n)
maFonct i on( gener at eur DI mpai r s( ) ) ;

Ce fragment de code semble invoquer 5 fois maFonct i on( ) , en lui passant successivement les
valeurs 1, 3, 5, 7 et 9. Mais que se passe-t-il si quelqu'un qui n'est pas conscient de ce contexte
d'utilisation introduit un appel gener at eur DI mpai r s( ) dans le corps de maFonct i on( ) ?
Le cas des fonctions membre
L'utilisation de variables statiques locales une fonction membre ncessite d'tre conscient du
fait qu'il n'existe pas un "exemplaire" de chaque fonction membre pour chaque instance de la
classe. En clair, quelle que soit l'instance utilise pour appeler la fonction membre, c'est le
mme jeu de variables locales statiques qui sera utilis.

Dans bien des cas, l'usage d'une variable membre s'avre plus judicieux que celui d'une
variable statique locale une fonction membre, car il permet chacune des instances de
maintenir des valeurs diffrentes.

Une classe "fonctionode" dote d'une variable membre permet, par exemple, de traiter
correctement le problme de notre gnrateur de nombres impairs :

cl ass gener at eur DI mpai r s
{
publ i c:
gener at eur DI mpai r s( ) : m_val eur ( - 1) {}
i nt oper at or ( ) ( ) {r et ur n m_val eur += 2; }
pr ot ect ed:
i nt m_val eur ;
};

L'usage de cette classe garantit que, quoi qu'entreprenne la fonction appele, elle ne peut en
aucun cas interfrer avec le gnrateur utilis par la fonction appelante (puisqu'elle n'y a pas
accs). Nous pouvons donc crire en toute scurit :

gener at eur DI mpai r s i mpai r Sui vant ;
i nt n;
f or ( n=0 ; n < 5 ; ++n)
maFonct i on( i mpai r Sui vant ( ) ) ;

Il arrive que l'unicit des variables locales statiques d'une fonction membre ne pose pas
problme, soit parce que c'est prcisment l'effet souhait, soit parce que la classe n'est pas
destine tre instancie plusieurs fois simultanment
1
(ce qui est, par exemple, le cas de la
plupart des classes dcrivant un dialogue avec l'utilisateur...). Le recours des variables
locales statiques prsente alors le double avantage de limiter le nombre de variables membre et
de ne pas rendre l'information accessible aux autres fonctions membre.

1
Si une classe ne supporte pas d'tre instancie plusieurs fois simultanment, il est de bonne politique de rendre ceci
impossible (en pratiquant, par exemple, un comptage d'occurrences tel que celui dcrit dans l'Annexe 3).
J-L Pris - 22/08/05
C++ - Leon 12 Allocation dynamique 5/9
Variables membre statiques vs. variables locales statiques d'une fonction membre
Les lecteurs qui ont parcouru l'Annexe 3 savent que le mot st at i c peut galement qualifier
des variables membres, ce qui peut prter confusion. En rsum :

Si une classe possde une variable membre statique, toutes les fonctions membre y ont accs
(puisqu'il s'agit d'une variable membre) et elles accderont toujours la mme variable, quelle
que soit l'instance au titre de laquelle elles sont excutes (puisque la variable est statique).

Si une fonction membre possde une variable locale statique, elle seule y aura accs (puisqu'il
s'agit d'une variable locale) et elle accdera toujours la mme variable, quelle que soit
l'instance au titre de laquelle elle est excute.
4 - Allocation dynamique
Rendre une variable locale statique est donc un moyen d'augmenter sa dure de stockage, sans
modifier pour autant sa porte. Ce moyen reste toutefois assez rudimentaire, car il n'offre de
contrle prcis ni sur le moment de la naissance de la variable (c'est forcment lors de la
premire excution du bloc) ni sur le moment de sa disparition (une variable statique ne
disparat qu' la fin de l'excution du programme). Lorsqu'une meilleure prcision dans le
contrle de la dure de stockage s'avre ncessaire, c'est au processus d'allocation dynamique
de la mmoire qu'il va nous falloir avoir recours.

La premire chose qu'il faut bien comprendre propos de l'allocation dynamique est que les
objets ainsi crs restent anonymes.

Selon la dfinition que nous avons adopte pour ce mot, ce ne sont donc pas des variables.

En l'absence de nom permettant de les dsigner, ces objets ne peuvent donc tre manipuls
qu' l'aide de pointeurs contenant leur adresse ou de rfrences leur tant associes.
Rserver de la mmoire avec new
Jusqu' prsent, la seule mthode dont nous disposions pour rendre un pointeur valide tait
d'utiliser l'oprateur "adresse de" pour obtenir l'adresse d'une variable du type adquat :

doubl e uneVar = 3. 14; 1
doubl e * pDoubl e = &uneVar ; 2

L'allocation dynamique fournit un moyen permettant de rserver une zone de mmoire d'une
taille correspondant au type de donne que l'on souhaite y stocker.

Il n'y a aucune restriction sur le type de donnes pour lesquelles newpeut rserver une zone de
stockage. Les types natifs ne bnficient d'aucun privilge de ce point de vue par rapport aux
types que vous avez crs vous-mme (en dfinissant une classe, par exemple).

L'oprateur qui effectue cette rservation est not new, et il faut, bien entendu, lui prciser le
type de donne qui doit pouvoir tre stock dans l'emplacement rclam. Si une zone de
mmoire de la taille ncessaire est disponible, l'oprateur new la marque comme tant rserve
et produit comme rsultat l'adresse de cette zone. Si la rservation de mmoire choue
(lorsque, par exemple, toute la mmoire de l'ordinateur qui excute le programme est dj
utilise), l'oprateur new donne un rsultat NULL.

C'est en tout cas la mthode qu'utilisait "traditionnellement" newpour signaler le problme. Si
vous disposez d'un compilateur "moderne", il est possible qu'il utilise par dfaut le mcanisme
des exceptions (cf. Leon 23). Vous pouvez alors lui demander explicitement de s'en tenir sa
premire mthode en utilisant new( not hr ow) en lieu et place de new.

Il convient donc, avant tout usage d'une adresse obtenue grce new, de vrifier que cette
adresse est valide. Si ce n'est pas le cas, le programme doit adopter un comportement adapt.

Dans le cas de programmes simples, l'chec d'une demande d'allocation de mmoire doit, au
minimum, conduire un arrt de l'excution du programme, prcd d'un message avertissant
l'utilisateur de la nature du problme. La faon correcte de mettre fin l'excution du
programme ne peut pas tre dcrite ici, car elle dpend du systme utilis. Dans le cadre de
projets plus ambitieux, il est parfois possible de mettre en place des stratgies palliatives, pour
viter d'avoir abandonner prmaturment l'excution du programme.

J-L Pris - 22/08/05
C++ - Leon 12 Allocation dynamique 6/9
Le fragment de code suivant propose un exemple de mise en uvre de ce systme :

doubl e * pDoubl e = NULL; 1
pDoubl e = new doubl e; 2
i f ( pDoubl e ! = NULL) 3
{ / / on peut ut i l i ser *pDoubl e comme s' i l s' agi ssai t du 4
*pDoubl e = 3. 14; / / nomd' une var i abl e de t ype doubl e 5
} 6
el se 7
/ / i l f aut pr endr e des mesur es ner gi ques ! 8

Dans cet exemple, une variable de type "pointeur sur doubl e" est tout d'abord cre (1). Cette
variable est initialise avec la constante NULL, qui indique clairement que la variable ne
contient pas, pour l'instant, l'adresse d'un doubl e (et qu'il faut donc se garder de toute
tentative de drfrencement).

Dans un second temps, l'oprateur new est utilis pour rclamer l'adresse d'une zone mmoire
susceptible de stocker une valeur de type doubl e. L'adresse produite par new est range dans
la variable pDoubl e (2).

L'oprateur newproduit une adresse. C'est donc bien dans une variable de type pointeur qu'il
convient de stocker ce rsultat. De toutes faons, essayer de drfrencer pDoubl e avant de lui
avoir donn un contenu valide ne pourrait conduire qu' une catastrophe. Il serait donc
doublement mal venu d'crire :

doubl e * pDoubl e = NULL;
* pDoubl e = new doubl e; / / une er r eur gr ossi r e !

En effet, drfrencer le pointeur nous conduit accder la zone de mmoire qu'il dsigne. Or
pDoubl e est de type "pointeur sur doubl e", ce qui signifie que la zone qu'il dsigne est destine
stocker une valeur dcimale, et non une adresse. De plus, comme pDoubl e n'est pas valide, la
valeur produite par newserait copie en mmoire un endroit imprvisible et vraisemblablement
utilis d'autres fins.

La suite du programme dpend de la valeur de pDoubl e. Si new a effectivement renvoy une
adresse valide, nous disposons d'une zone de mmoire qui peut contenir une valeur de type
double et laquelle nous accdons (5) en drfrenant pDoubl e. Dans le cas contraire, il ne
faut surtout pas essayer de drfrencer pDoubl e !

Il est galement possible (mais moins habituel) d'utiliser une rfrence pour dsigner l'objet cr
dynamiquement :

doubl e & unDoubl e = *new doubl e;
i f ( &unDoubl e ! = NULL)
{ / / on peut ut i l i ser unDoubl e comme s' i l s' agi ssai t du
unDoubl e = 3. 14; / / nomd' une var i abl e de t ype doubl e
}
el se
/ / i l f aut pr endr e des mesur es ner gi ques !

Remarquez que, pour "initialiser" la rfrence, il faut bien entendu drfrencer l'adresse
renvoye par new. Inversement, pour tester la validit de la rfrence, c'est l'adresse de l'objet
qu'elle dsigne qui doit tre vrifie. En contrepartie de ces efforts, nous obtenons la possibilit
de dsigner l'objet cr sans avoir utiliser le moindre oprateur.
Initialiser une zone mmoire rserve avec new
La demande de rservation d'une zone mmoire peut tre assortie d'une demande
d'initialisation de cette zone. La syntaxe employe dans ce cas est l'une de celles possibles pour
initialiser les variables : il suffit de mentionner entre parenthses la valeur souhaite :

i nt *pEnt i er = NULL; 1
pEnt i er = new i nt ( 12) ; / / i ni t i al i sat i on de l a zone avec l a val eur 12 2
Librer la mmoire avec del et e
Si elle n'est pas explicitement libre, la mmoire rserve l'aide de l'oprateur new reste
rserve jusqu' la fin de l'excution du programme. L'oprateur qui permet cette libration se
nomme del et e, et il faut, bien entendu, lui indiquer quel est le bloc de mmoire qui doit tre
J-L Pris - 22/08/05
C++ - Leon 12 Allocation dynamique 7/9
remis la disposition du systme. Assez naturellement, on dsigne le bloc de mmoire librer
en indiquant son adresse. Si l'on reprend l'exemple prcdent, la libration de la mmoire se
prsenterait de la faon suivante :

doubl e * pDoubl e = NULL; 1
pDoubl e = new doubl e; 2
i f ( pDoubl e ! = NULL) 3
{ 4
*pDoubl e = 3. 14; / / on peut ut i l i ser *pDoubl e comme s' i l s' agi ssai t du nom 5
/ / d' une var i abl e de t ype doubl e. 6
del et e pDoubl e; / / Lor squ' on n' en a pl us besoi n, on l i br e l a mmoi r e. 7
} 8
el se 9
/ / i l f aut pr endr e des mesur es ner gi ques ! 10

La notation employe ne doit pas vous conduire un contresens concernant l'effet de
del et e pDoubl e;

Contrairement ce qu'on pourrait croire, l'excution de cette instruction n'a aucun effet sur
pDoubl e (qui continue exister), ni mme sur le contenu de cette variable (qui peut
ventuellement continuer tre l'adresse du bloc de mmoire qui vient d'tre libr). Le seul
aspect de la variable pDoubl e qui soit certainement affect par l'excution de l'instruction en
question est sa validit en tant que pointeur. Aprs cette instruction, il devient videmment
dangereux de drfrencer pDoubl e, puisque ceci revient accder une zone de mmoire
dont nous ignorons dsormais quel est l'usage qui en est fait par le systme.

Cette situation est trs proche de celle signale page 3, propos du pointeur contenant l'adresse
d'une variable locale un bloc venant de se refermer. La disparition de la variable locale libre la
mmoire qui lui tait alloue, exactement comme del et e libre le bloc de mmoire dont l'adresse
lui est passe. Dans les deux cas, il nous reste un pointeur contenant l'adresse d'une zone de
mmoire dont l'usage nous est dsormais inconnu, c'est dire un pointeur invalide.

Etant donn que del et e a besoin de l'adresse du bloc librer, cet oprateur ne peut tre
utilis que dans la mesure o il existe une variable de type pointeur contenant l'adresse en
question. Il n'est pas pour autant ncessaire que le pointeur utilis cette occasion soit le
mme que celui ayant initialement reu l'adresse produite par new. Il arrive assez frquemment
que ce ne soit pas le cas, comme dans l'exemple suivant, o une fonction ut i l i sat r i ce( )
sous-traite al l oueI nt ( ) la tche consistant allouer la mmoire et mettre fin au
programme en cas d'chec de l'allocation.

i nt * al l oueI nt ( ) 1
{ 2
i nt * pEnt i er = new i nt ; 3
i f ( pEnt i er == NULL) 4
{ 5
/ / i ci doi vent f i gur er des i nst r uct i ons dest i nes met t r e f i n au pr ogr amme
} 6
r et ur n pEnt i er ; 7
} 8
/ / ***************************************************
voi d ut i l i sat r i ce( ) 9
{ 10
/ / appel s de l a f onct i on sous- t r ai t ant e
i nt * unPoi nt eur = al l oueI nt ( ) ; 11
i nt * unAut r e = al l oueI nt ( ) ; 12
/ / i ci peut f i gur er du code ut i l i sant *unPoi nt eur et *unAut r e 13
/ / l i br at i on de l a mmoi r e 14
del et e unPoi nt eur ; 15
del et e unAut r e; 16
} 17

Dans cet exemple, la seule utilisation de new figure (3) dans la fonction al l oueI nt ( ) , et elle
rserve une nouvelle zone de mmoire chaque appel de la fonction. Ces zones mmoire ne
sont pas destines tre utilises par al l oueI nt ( ) , mais par la fonction qui l'appelle. La
fonction al l oueI nt ( ) s'achve donc (7) en renvoyant comme rsultat l'adresse du bloc qui
J-L Pris - 22/08/05
C++ - Leon 12 Allocation dynamique 8/9
vient d'tre rserv (sauf, bien entendu, si l'allocation choue).
Remarquez bien que la fonction retourne la valeur du pointeur, et non la valeur contenue dans
la zone de mmoire dont l'adresse est dans ce pointeur. L'instruction r et ur n est donc applique
simplement sur la variable pEnt i er , sans opration de drfrencement.

L'adresse renvoye par al l oueI nt ( ) est stocke par la fonction ut i l i sat r i ce( ) dans l'une de
ses variables locales (11-12). Lorsque la fonction utilisatrice s'achve, elle libre tous les blocs
de mmoire allous dynamiquement en appliquant l'oprateur del et e chacun de ses
pointeurs (15-16). L'quilibre entre allocation et libration est donc obtenu ici avec un seul new
(3) contre deux del et e (15 et 16), chacune de ces trois instructions impliquant un pointeur
diffrent (pEnt i er , unPoi nt eur et unAut r e).

Le fait qu'appliquer del et e un pointeur affecte la disponibilit de la zone de mmoire
dsigne et non le pointeur lui-mme ne signifie pas seulement que la zone de mmoire peut
tre libre en la dsignant l'aide d'un autre pointeur que celui ayant recueilli son adresse
lors de l'allocation. Il signifie aussi que, si plusieurs pointeurs contiennent la mme adresse,
un seul del et e (portant sur n'importe lequel d'entre eux) les rendra tous invalides.

Lorsqu'un bloc de mmoire est libr l'aide de del et e, TOUS les pointeurs qui contiennent
son adresse deviennent invalides.
Les fuites de mmoire
Si un programme procde de nombreuses allocations dynamiques sans prendre soin de
librer les zones de mmoire devenues inutiles, la quantit de mmoire disponible finit
fatalement par tre puise, ce qui se traduit par l'chec d'une des demandes d'allocation.

Mme si l'usage que fait votre programme de la mmoire est drisoire vis vis de la capacit
mmoire totale de la machine que vous utilisez, laisser la fin du programme librer pour vous
la mmoire que vous avez rquisitionne l'aide de new est une pratique de sauvage.

Que va-t-il se passer si votre programme est excut sur un ordinateur moins richement dot en
mmoire ? Et si de trs nombreux programmes diffrents sont simultanment excuts ? Et si
plusieurs exemplaires de votre programme sont excuts en mme temps ? Et si quelqu'un
d'autre (ou vous-mme, dans six mois) essaie de gnraliser votre programme et lui donne une
ampleur que vous n'aviez pas prvue ? Mme si rien de tout cela ne se produit, il est clair que,
dans un programme bien conu, il est assez facile de librer proprement tous les blocs allous
avec new. Si votre programme ne le fait pas, cela en dit long sur la qualit gnrale de sa
conception et suggre que d'autres erreurs pourraient bien y tre tapies.

A chaque allocation d'un bloc de mmoire l'aide de l'oprateur new doit correspondre une
libration du bloc en question l'aide de l'oprateur del et e.

Lorsqu'un programme ne respecte pas cette rgle, on dit qu'il prsente une "fuite de mmoire"
(memory leak, en anglais), et il s'agit d'un indice peu prs aussi rassurant qu'une flaque
d'huile sous la voiture d'occasion que vous vous apprtez acheter.
A quoi sert rellement l'allocation dynamique ?
D'une faon gnrale, l'allocation dynamique s'avre indispensable ds qu'un nombre
important ou imprvisible de donnes doivent tre manipules.

La plupart du temps, vous n'utiliserez pas directement les oprateurs new et del et e mais des
classes conteneur (QVal ueLi st ou QMap, par exemple) qui assurent moindre frais une gestion
correcte de l'allocation dynamique.

Il reste nanmoins deux cas o le recours explicite l'allocation dynamique s'imposera :

- lorsque certains widgets proposs l'utilisateur seront mis en place par le programme lui-
mme, au cours de son excution (et non prpositionns l'aide de Qt Designer).

Les widgets gnrs dynamiquement sont habituellement confis un objet Qt prexistant, qui
en prend la responsabilit : la destruction du widget est alors assure automatiquement en
temps voulu, et aucun appel explicite del et e ne doit tre fait.

- lorsque vous utiliserez des structures de donnes autres que celles prises en charge par les
conteneurs Qt (cf. Leons 17, 18, 19, 20 et 21) ;
J-L Pris - 22/08/05
C++ - Leon 12 Allocation dynamique 9/9
5 - Bon, c'est gentil tout a, mais a fait dj 7 pages. Qu'est-ce que
je dois vraiment en retenir ?
1) La porte d'une variable est la portion du programme o le nom de la variable peut tre
utilis.

2) En gnral, la dure de stockage d'une variable correspond sa porte : de la dfinition de la
variable jusqu' la fin du bloc o cette dfinition figure.

3) Lorsque, l'intrieur de la porte d'une variable, on dfinit une variable homonyme, cette
nouvelle variable masque la premire (qui se trouve donc hors de porte, jusqu' la
disparition de la seconde variable).

4) Rendre une variable statique prolonge sa dure de stockage jusqu' la fin de l'excution du
programme, sans modifier sa porte.

5) On peut obtenir une zone de stockage convenant une donne d'un type quelconque en
utilisant l'oprateur new.

6) L'oprateur new produit l'adresse de la zone de mmoire rserve, et cette adresse peut tre
stocke dans un pointeur du type adquat.

7) Si new ne parvient pas rserver la zone de mmoire demande, l'adresse qu'il produit est
NULL.

8) Les blocs de mmoire rservs l'aide de new doivent tre librs l'aide de del et e.

9) Drfrencer un pointeur contenant l'adresse d'une zone de mmoire qui n'est pas (ou plus)
consacre au stockage d'une donne d'un type correspondant celui du pointeur est
rarement une bonne ide.

J-L Pris - 22/08/05