Partie I
Cette entrée de la FAQ C++ explique pourquoi on peut avoir envie de surcharge new
et delete
opérateurs pour sa propre classe. Cette FAQ tente d'expliquer comment on le fait dans un standard conforme.
La mise en œuvre d'une coutume new
de l'opérateur
La norme C++ (§18.4.1.1) définit operator new
comme:
void* operator new (std::size_t size) throw (std::bad_alloc);
Le C++ standard spécifie la sémantique que des versions personnalisées de ces opérateurs ont à obéir au §3.7.3 et §18.4.1
Résumons les exigences.
Exigence n ° 1: Il doit allouer dynamiquement au moins size
octets de mémoire et retourne un pointeur vers la mémoire allouée. Citation de la norme C++, section 3.7.4.1.3:
La fonction d'allocation vise à répartir le montant demandé de stockage. Si elle est réussie, elle doit renvoyer l'adresse de début d'un bloc de stockage dont la longueur en octets doivent être au moins aussi grand que la taille demandée...
La norme impose en outre:
...Le pointeur retourné doit être correctement alignés de sorte qu'il peut être converti en un pointeur de chaque type d'objet, puis utilisé pour accéder à l'objet ou le tableau dans le stockage alloué (jusqu'à ce que le stockage est explicitement libéré par un appel à une fonction de libération). Même si la taille de l'espace requis est égal à zéro, la requête peut échouer. Si la demande aboutit, la valeur retournée est une non-valeur de pointeur null (4.10) p0 différente de celle précédemment renvoyée valeur p1, à moins que la valeur de p1 est ensuite transmis à un opérateur delete
.
Cela nous donne en outre à des exigences importantes:
Exigence n ° 2: La fonction d'allocation mémoire nous utilisons (habituellement malloc()
ou certains autres allocateur personnalisé) doit retourner une correctement alignés pointeur vers la mémoire allouée, qui peut être converti en un pointeur d'un type d'objet et utilisé pour accéder à l'objet.
Exigence n ° 3: Notre propre opérateur new
doit retourner une légitime pointeur de même lors de zéro octets sont demandés.
L'un des manifestes les exigences qui peuvent même être déduite à partir de new
prototype:
Exigence n ° 4: Si new
ne peut pas allouer de la mémoire dynamique de la taille demandée, alors il doit lever une exception de type std::bad_alloc
.
Mais! Il n'y a plus que ce que rencontre l'oeil: Si vous regardez de plus près à l' new
de l'opérateur de la documentation (citation de la norme suit plus bas), il indique:
Si set_new_handler a été utilisé pour définir une new_handler fonction, ce new_handler
fonction est appelée par le standard de la définition par défaut de operator new
si il ne peut pas allouer de la demande de stockage par son propre.
Pour comprendre comment notre coutume new
besoins à l'appui de cette exigence, il faut comprendre:
Quel est le new_handler
et set_new_handler
?
new_handler
est une définition de type d'un pointeur vers une fonction qui prend et ne renvoie rien, et
set_new_handler
est une fonction qui prend et retourne un new_handler
.
set_new_handler
s'paramètre est un pointeur vers la fonction de nouvel opérateur devrait appeler si il ne peut pas allouer de la mémoire demandée. Sa valeur de retour est un pointeur précédemment enregistré fonction de gestionnaire, ou null si il n'y avait pas de précédent gestionnaire.
Un moment opportun pour un exemple de code pour mettre les choses au clair:
#include <iostream>
#include <cstdlib>
// function to call if operator new can't allocate enough memory or error arises
void outOfMemHandler()
{
std::cerr << "Unable to satisfy request for memory\n";
std::abort();
}
int main()
{
//set the new_handler
std::set_new_handler(outOfMemHandler);
//Request huge memory size, that will cause ::operator new to fail
int *pBigDataArray = new int[100000000L];
return 0;
}
Dans l'exemple ci-dessus, operator new
(le plus probable) sera impossible d'allouer de l'espace pour 100 000 000 d'entiers, et la fonction outOfMemHandler()
sera appelée, et le programme s'arrêtera après l'émission d'un message d'erreur.
Il est important de noter ici que, lors de l' operator new
est incapable de remplir une demande de mémoire, il appelle l' new-handler
fonction à plusieurs reprises jusqu'à ce qu'il peut trouver suffisamment de mémoire ou il n'y a plus de nouveaux gestionnaires. Dans l'exemple ci-dessus, à moins que nous appelons std::abort()
, outOfMemHandler()
serait appelé à plusieurs reprises. Par conséquent, le gestionnaire doit s'assurer que la prochaine allocation réussit, ou inscrire un autre gestionnaire, ou n'enregistrent pas de gestionnaire, ou pas de retour (c'est à dire la fin du programme). Si il n'y a pas de nouvelles de gestionnaire et de l'allocation échoue, l'opérateur va lancer une exception.
Suite 1