nouveau et supprimer (C++) - new and delete (C++)


Dans le langage de programmation C++ , new et delete sont une paire de constructions de langage qui effectuent l'allocation dynamique de mémoire , la construction d' objets et la destruction d'objets .

Aperçu

À l'exception d'une forme appelée "placement new" , l' opérateur new désigne une demande d'allocation de mémoire sur le tas d' un processus . Si suffisamment de mémoire est disponible, new initialise la mémoire, en appelant les constructeurs d'objets si nécessaire, et renvoie l'adresse à la mémoire nouvellement allouée et initialisée. Une nouvelle demande, dans sa forme la plus simple, se présente comme suit :

p = new T;

p est un pointeur précédemment déclaré de type T (ou d'un autre type auquel un pointeur T peut être affecté, comme une superclasse de T ). Le constructeur par défaut de T , le cas échéant, est appelé pour construire une instance de T dans la mémoire tampon allouée.

S'il n'y a pas assez de mémoire disponible dans le magasin libre pour un objet de type T , la nouvelle requête indique un échec en lançant une exception de type std::bad_alloc . Cela supprime la nécessité de vérifier explicitement le résultat d'une allocation.

La contrepartie de désallocation de new est delete , qui appelle d'abord le destructeur (le cas échéant) sur son argument, puis renvoie la mémoire allouée par new à la mémoire libre. A chaque appel à new doit correspondre un appel à supprimer ; ne pas le faire provoque des fuites de mémoire .

la nouvelle syntaxe a plusieurs variantes qui permettent un contrôle plus fin sur l'allocation de mémoire et la construction d'objets. Une syntaxe de type appel de fonction est utilisée pour appeler un constructeur différent de celui par défaut et lui passer des arguments, par exemple,

p = new T(argument);

appelle un constructeur T à un seul argument au lieu du constructeur par défaut lors de l'initialisation du tampon nouvellement alloué.

Une variante différente alloue et initialise des tableaux d'objets plutôt que des objets uniques :

p = new T [N];

Cela demande un tampon mémoire du magasin libre qui est suffisamment grand pour contenir un tableau contigu de N objets de type T , de manière contiguë, et appelle le constructeur par défaut sur chaque élément du tableau.

La mémoire allouée avec new[] doit être désallouée avec l' opérateur delete[] , plutôt que delete . L'utilisation du formulaire inapproprié entraîne un comportement indéfini . Les compilateurs C++ ne sont pas obligés de générer un message de diagnostic pour l'utilisation du mauvais formulaire.

La norme C++11 spécifie une syntaxe supplémentaire,

p = new T[N] {initializer1, ..., initializerN};

qui initialise chaque p[ i ] à l' initialiseur i+1 .

La gestion des erreurs

Si new ne peut pas trouver suffisamment de mémoire pour traiter une demande d'allocation, il peut signaler son erreur de trois manières distinctes. Premièrement, la norme ISO C++ permet aux programmes d'enregistrer une fonction personnalisée appelée new_handler avec le runtime C++ ; si c'est le cas, cette fonction est appelée chaque fois que new rencontre une erreur. Le new_handler peut tenter de libérer de la mémoire ou terminer le programme s'il ne le peut pas.

Si aucun new_handler n'est installé, new lève à la place une exception de type std::bad_alloc . Ainsi, le programme n'a pas besoin de vérifier la valeur du pointeur renvoyé, comme c'est l'habitude en C ; si aucune exception n'a été levée, l'allocation a réussi.

La troisième méthode de gestion des erreurs est fournie par la forme variante new(std::nothrow) , qui spécifie qu'aucune exception ne doit être levée ; à la place, un pointeur nul est renvoyé pour signaler une erreur d'allocation.

Surcharge

L' opérateur new peut être surchargé de sorte que des types (classes) spécifiques utilisent des algorithmes d'allocation de mémoire personnalisés pour leurs instances. Par exemple, voici une variante du modèle singleton où le premier nouvel appel Singleton alloue une instance et tous les appels suivants renvoient cette même instance :

#include <cstdlib>
#include <cstddef>

class Singleton {
public:
  static void* operator new(std::size_t size) {
    if (!instance) {
      instance = std::malloc(size);
    }
    refcount++;
    return instance;
  }

  static void operator delete(void*) noexcept {
    if (--refcount == 0) {
      std::free(instance);
      instance = nullptr;
    }
  }

private:
  static void* instance = nullptr;
  static std::size_t refcount = 0;
};

Cette fonctionnalité était disponible dès le début de l'histoire du C++, bien que le mécanisme de surcharge spécifique ait changé. Il a été ajouté au langage car les programmes C++ orientés objet avaient tendance à allouer de nombreux petits objets avec new , qui utilisait en interne l'allocateur C (voir § Relation avec malloc et free ); qui, cependant, a été optimisé pour les allocations moins nombreuses et plus importantes effectuées par les programmes C typiques. Stroustrup a signalé que dans les premières applications, la fonction C malloc était « le goulot d'étranglement des performances le plus courant dans les systèmes réels », les programmes passant jusqu'à 50 % de leur temps dans cette fonction.

void *operator new(size_t size)

La construction du langage C++ qui alloue uniquement de la mémoire est appelée . Il est utilisé par les nouveaux dans la phase d'allocation. Il peut être remplacé par classe ou globalement pour définir un allocateur de mémoire spécifique. void *operator new(size_t size)

Relation avec malloc et free

Étant donné que le C++ standard subsume la bibliothèque standard C , les routines d' allocation de mémoire dynamique C malloc , calloc , realloc et free sont également disponibles pour les programmeurs C++. L'utilisation de ces routines est déconseillée pour la plupart des utilisations, car elles n'effectuent pas d'initialisation et de destruction d'objets. new et delete ont, en effet, été introduits dans la première version de C++ (alors appelée " C with Classes ") pour éviter la nécessité d'une initialisation manuelle des objets.

Contrairement aux routines C, qui permettent d'agrandir ou de réduire un tableau alloué avec realloc , il n'est pas possible de modifier la taille d'un tampon mémoire alloué par new[] . La bibliothèque standard C++ fournit à la place un tableau dynamique (collection) qui peut être étendu ou réduit dans sa classe de modèle std::vector .

Le standard C++ ne spécifie aucune relation entre new / delete et les routines d'allocation de mémoire C, mais new et delete sont généralement implémentés en tant que wrappers autour de malloc et free . Mélanger les deux familles d'opérations, par exemple libérer de la mémoire nouvellement allouée ou supprimer de la mémoire mallocée , provoque un comportement indéfini et, en pratique, peut conduire à divers résultats catastrophiques tels que l'échec de la libération des verrous et donc le blocage .

Voir également

Les références