ProgrammazioneSviluppatore C++

Che cos'è 'placement new' in C++? A cosa e come viene utilizzato questo meccanismo?

Supera i colloqui con l'assistente IA Hintsage

Risposta

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:

  • Consente di implementare allocatori personalizzati.
  • Riduce i costi per una nuova allocazione di memoria.
  • Non chiama l'allocatore standard — controllo sulla gestione della memoria.

Domanda trabocchetto

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!

Esempi di errori reali a causa della mancanza di conoscenza delle sottigliezze del tema


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 new per 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 new all'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.