Pollux> alors le new et le delete sont plus compliqués que ça. Tu as l'opérateur new de ta classe.
Et tu as six fonctions d'allocations, appelées new également, définies au niveau global.
Et enfin il faut distinguer ça des
new-expression qui sont les bouts de code provoquant l'allocation (x = new Classe
L'opérateur peut être redéfini, ces six fonctions également. Et il est possible de définir de nouvelles fonctions d'allocations au niveau global.
Quand le programme rencontre une
new-expression, il génère la séquence suivante :
- la new-expression comment par allouer de la mémoire =>
---- si la classe a un opérateur new avec des paramètres correspondant, c'est lui qui est appelé
---- sinon le comportement par défaut s'applique =>
-------- la new-expression détermine la taille nécessaire. Pour un objet simple, c'est sizeof(objet), pour un tableau ça peut être davantage pour des questions d'alignement.
-------- la new-expression fait appel à la fonction d'allocation appropriée
- la new-expression initie la construction de l'objet
(on passera sur la gestion des exceptions intervenant dans l'allocation ou la construction...ainsi que sur la définition de la construction d'un objet)
Il faut repasser un coup sur "la fonction d'allocaton appropriée". Il en existe 6, et elles peuvent être redéfinies séparément. Elles sont :
void * operator new(std :: size_t size ) throw (std :: bad_alloc ); // new normal
void * operator new(std :: size_t size , const std :: nothrow_t & ) throw (); // new nothrow
void * operator new (std :: size_t size , void * ptr ) throw (); // placement-new
void * operator new []( std :: size_t size ) throw (std :: bad_alloc ); // new tableau normal
void * operator new []( std :: size_t size , const std :: nothrow_t & ) throw ();// new tableau nothrow
void * operator new []( std :: size_t size , void * ptr ) throw (); // placement-new tableau
1) Le new normal, je pense qu'il n'y a pas trop de commentaire à faire dessus, c'est quasiment un malloc (quoiqu'il obtienne sa mémoire depuis un autre pool en général), sauf qu'en cas d'échec d'allocation il lève une exception std::bad_alloc
2) Le new nothrow, c'est encore plus proche du malloc, vu qu'il renvoie 0 au lieu de lever une exception. On peut forcer la
new-expression à utiliser le new nothrow de cette façon => X = new(std::nothrow) Classe;
3) le placement-new est utilisé pour allouer l'objet à l'adresse passée en paramètre
4 à 6) idem que les premiers mais pour des tableaux.
Au vu de ça, je pense que ce que tu proposais n'est pas de créer un opérateur new qui utilise malloc, vu que ça serait encore dans la sémantique new normale, mais plutôt d'allouer des objets dans une zone mémoire réservée avec malloc. Ca donnerait ceci =>
void * buffer = malloc(sizeof(Classe));
Classe * X = new(buffer) Classe;
Dans ce cas, pour libérer ton objet, tu dois faire ça =>
X->~Classe();
free(buffer);
En terme de standard c'est plus compliqué, ce qu'il se passe si tu n'appelles pas le destructeur n'est défini nulle part. La seule chose qui est dite, c'est que dans le cas d'un destructeur trivial (donc avec que des membres et classes de bases à destructeurs récursivement triviaux), le compilateur peut ne pas appeler les destructeurs.
Mais ça ne retire rien à ce que je disais, vu que le compilateur sait très bien s'il a ajouté ou non des choses qui font qu'il doit appeler impérativement les destructeurs triviaux; en revanche toi tu ne le sais pas.