Comme on l'a vu précédemment, quand un objet est créé par un
new
, un operator new()
est appelé.
Un X::operator new()
est toujours un membre
statique, son premier argument est toujours du type
size_t
et retourne un void *
.
De même un X::operator delete()
est toujours
statique, retourne void
et a comme premier argument un
void *
(éventuellement un deuxième argument de
type size_t
donnant la taille de ce qui doit être
détruit).
L'opérateur new peut être surchargé, alors qu'il ne peut y avoir qu'un seul l'opérateur delete par classe.
Dans de très nombreux cas, le temps d'exécution d'un programme provient en grande partie de l'allocation dynamique. Pour une classe donnée, la stratège d'allocation peut être optimisée (par exemple si on sait que toutes les allocations auront la même taille), il est donc souvent utile de définir les opérateurs new et delete.
Il ne faut pas oublier cependant qu'un tableau d'objets de classe
A n'est pas considéré comme un objet de classe
A et que donc un new A [10]
n'appelle pas l'opérateur
A::new
, mais l'opérateur new global. De la même façon,
l'appel de delete [] A
appellera l'opérateur global, alors que
delete A
appellera l'opérateur A::delete
.
Exemple :
#define N_A 100 class A{ private: int i, j; public: A(){/*. . . */} void *operator new(size_t); void operator delete(void *); }; class Alloc_A{ friend class A; static A * Mem; static char occupe[N_A]; static int prem_lib(); }; A *Alloc_A::Mem=new A[N_A]; // obligatoire // appal A::A() char Alloc_A::occupe[N_A]; // obligatoire int Alloc_A::prem_lib(){ for(int i=0;i<N_A;i++)if(!occupe[i]){ occupe[i]=1;return i;} return -1; } void A::operator delete(void *p){ Alloc_A::occupe[(A *)p -Alloc_A::Mem] = 0; } void *A::operator new(size_t t){ int x; if ((x=Alloc_A::prem_lib())==-1) return 0; return Alloc_A::Mem+x; } void main(){ A *p=new A; // Alloc_A::new et A::A() A *t=new A[10]; // ::new et 10xA::A() }