placement new è una forma particolare dell'operatore new in C++. Permette di posizionare un oggetto a un indirizzo specificato in un'area di memoria già allocata. Viene solitamente utilizzato per la gestione manuale della memoria ed è alla base del funzionamento degli allocatori, del pooling degli oggetti e della serializzazione in buffer fissi.
Sintassi:
#include <new> void* memory = malloc(sizeof(MyClass)); MyClass* obj = new (memory) MyClass(args...); // chiama il costruttore all'indirizzo memory
Qui la memoria viene allocata separatamente (ad esempio, tramite malloc o un allocatore), e poi il costruttore della classe viene chiamato in quella memoria. Non dimenticare di chiamare esplicitamente il distruttore:
obj->~MyClass(); free(memory);
Vantaggi:
Può essere utilizzato lo stesso blocco di memoria per posizionare più oggetti consecutivamente tramite 'placement new', e quali conseguenze comporta?
Una risposta errata comune è che si possono posizionare nuovi oggetti in memoria senza preoccuparsi dello stato precedente. In realtà, se nella stessa area di memoria si posiziona un nuovo oggetto sovrascrivendo un vecchio senza chiamare il suo distruttore, si verificherà una perdita di risorse, e la chiamata del distruttore porterà a UB.
Esempio:
void* place = malloc(sizeof(A)); A* a = new (place) A(); B* b = new (place) B(); // l'oggetto A non è stato distrutto! UB!
Storia
In un sistema ad alta capacità, uno sviluppatore ha implementato un pool di oggetti tramite
malloc+placement new, ma ha dimenticato di chiamare il distruttore quando l'oggetto veniva restituito al pool. Di conseguenza, le risorse (descrittori di sistema all'interno degli oggetti) non venivano liberate, portando a perdite e al "blocco" dei server.
Storia
In un progetto per la serializzazione dei dati binari, è stato utilizzato un buffer e
placement newper decodificare oggetti in loco. Tuttavia, si è dimenticato di inizializzare la memoria con zeri prima della posizione, il che ha portato alla lettura di dati non inizializzati e a strani bug durante l'uso di strutture POD.
Storia
Uno dei moduli ha migrato alla posizionamento di array di oggetti utilizzando
placement newall'interno di un blocco già allocato. Dopo aver aggiunto membri del classi con distruttori non banali, si sono verificati crash dell'applicazione — si è dimenticato che ora è necessario chiamare esplicitamente il distruttore per ogni elemento durante la pulizia, cosa che prima non era necessaria.