Apprendre C++ avec Qt : Annexe 4 Surcharger les oprateurs new et del et e
1 - L'oprateur new Il est possible de surcharger l'oprateur new soit globalement soit spcifiquement pour une classe. En cas de surcharge globale, la fonction oprateur sera appele lors de chaque utilisation de new, et doit donc tre assez gnrale pour allouer dynamiquement la mmoire ncessaire 1 , quel que soit le type de l'objet dont la cration est demande. Lorsque l'oprateur new est surcharg par une fonction membre, en revanche, celle-ci ne sera appele que lors de la cration dynamique d'une instance de la classe en question. Caractristiques d'une fonction oper at or new( ) Qu'elle soit globale ou membre d'une classe, une fonction oper at or new( ) doit respecter certaines contraintes lies la nature un peu particulire de l'opration qu'elle effectue.
- Toute fonction surchargeant new doit tre de type "pointeur gnrique" et doit renvoyer l'adresse d'une zone de mmoire alloue dynamiquement par ses soins.
Le type "pointeur gnrique" ne sera tudi en dtail que dans la Leon 22. En l'occurrence, son utilisation comme type de la fonction oper at or new( ) n'a gure de consquences, car la valeur renvoye est automatiquement transtype lors de son affectation au pointeur auquel elle est destine (il s'agit l d'un cas exceptionnel : l'affectation d'une valeur de type "pointeur gnrique" une variable d'un autre type exige normalement un transtypage explicite).
- Une fonction surchargeant new peut recevoir un ou plusieurs paramtres.
- Le premier paramtre de toute fonction surchargeant new doit tre de type si ze_t 2 , et la valeur servant initialiser ce paramtre ne doit pas tre fournie lors de l'appel de la fonction (elle sera automatiquement gnre par le compilateur : il s'agit en fait de la taille de la zone de mmoire requise).
- Etant donn que la fonction oper at or new( ) ne saurait tre invoque au titre de l'objet concern (qui n'existe pas encore), cette fonction est automatiquement rendue statique (cf. Annexe 3) si elle est membre d'une classe. Le processus de cration dynamique d'une instance Il est important de bien comprendre que l'excution d'une fonction oper at or new( ) n'est que la premire tape de la cration dynamique d'une instance. Une fois cette excution termine, un constructeur est automatiquement appel, de faon initialiser la zone de mmoire qui vient d'tre rserve. La version du constructeur qui sera utilise dpend des arguments ventuellement fournis. Ainsi, si
CTr uc *unTr uc = new CTr uc;
appelle la fonction oper at or new( ) , puis le constructeur par dfaut,
CTr uc *unTr uc = new CTr uc( 17) ;
appellera la fonction oper at or new( ) , puis le constructeur de transtypage d'i nt vers CTr uc (ce qui suppose, bien entendu, qu'un tel constructeur ait t dfini).
1 Il ne serait VRAIMENT pas raisonnable d'envisager une fonction surchargeant new et n'assurant pas l'quivalent fonctionnel d'une allocation dynamique de mmoire en vue de la cration d'un objet... 2 La dfinition du type size_t est donne dans le fichier stddef.h. Il s'agit d'un simple alias destin masquer au code source le fait que, selon les systmes, la taille des objets s'exprime sur deux ou quatre octets. Document du 05/06/07 - Retrouvez la version la plus rcente sur http://www.up.univ-mrs.fr/wcpp C++ - Annexe 4 Oprateurs new et del et e 2/3
Exemples Voici une fonction oper at or new( ) globale, qui pourrait servir tudier le comportement (ou mme dboguer...) un programme utilisant l'allocation dynamique.
voi d * oper at or new( si ze_t t ai l l e) 1 { 2 voi d * adr esse = mal l oc( t ai l l e) ; 3 cout << " quel qu' un vi ent d' al l ouer " << t ai l l e << " oct et s\ n" ; 4 r et ur n adr esse; 5 } 6
La fonction ci-dessus obtient l'allocation d'une zone de mmoire de la taille ncessaire en faisant appel la fonction mal l oc( ) . Cette fonction fait partie de la librairie standard du langage C et, ce titre, est disponible pour un programme C++, pour peu qu'il y figure une directive #i ncl ude " st dl i b. h" . Dans un programme rel, on peut penser que, si le programmeur se donne la peine de surcharger new, c'est parce qu'il a une ide bien prcise de la faon dont il souhaite que la gestion de la mmoire soit effectue. Il sera bien entendu alors conduit mettre en place un dispositif plus complexe qu'un simple appel mal l oc( ) .
Si on s'intresse plus particulirement la classe CTr uc, on peut se contenter d'examiner les demandes d'allocation dynamique concernant les objets de ce type :
voi d * CTr uc: : oper at or new( si ze_t t ai l l e) 1 { 2 voi d * adr esse = mal l oc( t ai l l e) ; 3 cout << " quel qu' un vi ent de r cl amer l ' al l ocat i on d' un CTr uc\ n" ; 4 r et ur n adr esse; 5 } 6 Utilisation d'un oprateur new surcharg Qu'il s'agisse d'une fonction globale ou d'un membre d'une classe, l'usage d'une fonction oper at or new( ) ne fait pas intervenir une syntaxe diffrente de celle devant tre utilise lors d'une allocation dynamique utilisant l'oprateur new prdfini :
CTr uc * pt r = new CTr uc;
Lorsque la fonction oper at or new( ) comporte plusieurs arguments, il est bien entendu indispensable de transmettre, lors de l'appel de la fonction, les valeurs destines l'initialisation de ces paramtres. Si l'on suppose que la classe CTr uc comporte une fonction operator new( ) dfinie ainsi :
voi d * CTr uc: : oper at or new( si ze_t t ai l l e, doubl e val ) 1 { 2 / / l e code i nsr i ci peut ut i l i ser val comme i l l ' ent end } 3
On transmettra la valeur requise en crivant
CTr uc * pt r = new( 5. 2) CTr uc;
Il ne faut pas confondre les valeurs destines aux paramtres de l'oprateur new avec les valeurs qui doivent tre transmises au constructeur qui sera appel une fois l'allocation de mmoire effectue. Si la classe CTr uc comporte, en plus de l'oprateur new dcrit ci-dessus, un constructeur de transtypage partir d'un doubl e, on pourra tre amen crire :
CTr uc * pt r = new( 5. 2) CTr uc( 3. 14) ; 2 - L'oprateur del et e Une fonction oper at or del et e( ) ne doit pas renvoyer de valeur. Elle doit accepter un paramtre de type "pointeur gnrique" qui indique l'adresse de la zone de mmoire librer et, ventuellement, un paramtre de type si ze_t qui donnera la taille de cette zone. Ces deux valeurs sont automatiquement fournies par le compilateur et n'ont donc pas figurer dans le J-L Pris - 05/06/07 C++ - Annexe 4 Oprateurs new et del et e 3/3
code appelant. L'excution d'une fonction oper at or del et e( ) est la dernire tape de la destruction d'une instance cre de faon dynamique : elle est prcde de l'appel du destructeur de la classe concerne. Si oper at or new( ) est dfini ainsi :
voi d * CTr uc: : oper at or new( si ze_t t ai l l e) 1 { 2 voi d *adr esse = mal l oc( t ai l l e) ; 3 cout << " quel qu' un vi ent de r cl amer l ' al l ocat i on d' un CTr uc" << endl ; 4 r et ur n adr esse; 5 } 6
il semble logique que oper at or del et e( ) le soit ainsi :
voi d CTr uc: : oper at or del et e( voi d * aTuer , si ze_t t ai l l e) 1 { 2 f r ee( aTuer ) ; / / f r ee( ) est l a f onct i on l i br ant l a mmoi r e al l oue par mal l oc( ) 3 cout << " mor t du CTr uc qui habi t ai t l ' adr esse " << aTuer <<endl ; 4 cout << t ai l l e << " oct et s ont t l i br s. " << endl ; 5 } 6