ProgrammationDéveloppeur C++

Qu'est-ce que 'placement new' en C++ ? À quoi sert ce mécanisme et comment l'utilise-t-on ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse

placement new est une forme particulière de l'opérateur new en C++. Il permet de placer un objet à une adresse donnée dans une zone de mémoire déjà allouée. Il est généralement utilisé pour la gestion manuelle de la mémoire, sous-tend le fonctionnement des allocateurs, du pooling d'objets et de la sérialisation dans des tampons fixes.

Syntaxe :

#include <new> void* memory = malloc(sizeof(MyClass)); MyClass* obj = new (memory) MyClass(args...); // appelle le constructeur à l'adresse memory

Ici, la mémoire est allouée séparément (par exemple, via malloc ou un allocateur), puis le constructeur de la classe est appelé dans cette mémoire. N'oubliez pas d'appeler explicitement le destructeur :

obj->~MyClass(); free(memory);

Avantages :

  • Permet de réaliser vos propres allocateurs.
  • Réduit les coûts liés à une nouvelle allocation de mémoire.
  • N'appelle pas l'allocateur standard — contrôle de la gestion de la mémoire.

Question piège

Un même bloc de mémoire peut-il être utilisé pour placer plusieurs objets consécutivement avec 'placement new', et quelles en sont les conséquences ?

Une réponse incorrecte courante — il est possible de placer de nouveaux objets en mémoire sans se soucier de l'état précédent. En réalité, si un nouvel objet est placé dans la même zone de mémoire qu'un ancien sans appeler son destructeur, cela entraîne une perte de ressources, et l'appel du destructeur entraînera ensuite un comportement indéfini.

Exemple :

void* place = malloc(sizeof(A)); A* a = new (place) A(); B* b = new (place) B(); // l'objet A n'est pas détruit ! comportement indéfini !

Exemples d'erreurs réelles dues à l'ignorance des subtilités du sujet


Histoire

Dans un système à forte charge, un développeur a mis en œuvre un pool d'objets via malloc + placement new, mais a oublié d'appeler le destructeur lors du retour d'un objet au pool. En conséquence, les ressources (descripteurs système à l'intérieur des objets) n'ont pas été libérées, entraînant des fuites et un "gel" des serveurs.



Histoire

Dans un projet de sérialisation de données binaires, un tampon et placement new étaient utilisés pour décoder des objets sur place. Cependant, ils ont oublié d'initialiser la mémoire à zéro avant de placer, ce qui a conduit à la lecture de données non initialisées et à des bogues étranges lors de l'utilisation de structures POD.



Histoire

Un des modules a migré vers le placement de tableaux d'objets à l'aide de placement new à l'intérieur d'un bloc préalablement alloué. Après l'ajout de nouveaux membres à l'intérieur de la classe avec des destructeurs non triviaux, des plantages de programme sont survenus — ils ont oublié qu'il fallait maintenant appeler explicitement le destructeur pour chaque élément lors du nettoyage, ce qui n'était pas nécessaire auparavant.