placement new ist eine besondere Form des new Operators in C++. Es ermöglicht die Platzierung eines Objekts an einer angegebenen Adresse im bereits reservierten Speicherbereich. Normalerweise wird es für manuelles Speichermanagement verwendet, liegt der Funktionsweise von Allokatoren, Objekt-Pooling und Serialisierung in feste Puffer zugrunde.
Syntax:
#include <new> void* memory = malloc(sizeof(MyClass)); MyClass* obj = new (memory) MyClass(args...); // ruft den Konstruktor an der Adresse memory auf
Hier wird der Speicher separat reserviert (z.B. über malloc oder einen Allokator), und dann wird der Konstruktor der Klasse in diesem Speicher aufgerufen. Vergessen Sie nicht, den Destruktor explizit aufzurufen:
obj->~MyClass(); free(memory);
Vorteile:
Kann derselbe Speicherblock verwendet werden, um mehrere Objekte nacheinander mit 'placement new' zu platzieren, und welche Folgen hat dies?
Eine häufige falsche Antwort ist — man kann neue Objekte im Speicher platzieren, ohne sich um den vorherigen Zustand zu kümmern. Tatsächlich führt das Platzieren eines neuen Objekts über einem alten Objekt ohne Aufruf seines Destruktors in demselben Speicherbereich zu einem Ressourcenleck und der Aufruf des Destruktors führt später zu UB.
Beispiel:
void* place = malloc(sizeof(A)); A* a = new (place) A(); B* b = new (place) B(); // Objekt A wird nicht zerstört! UB!
Geschichte
In einem hoch belasteten System implementierte ein Entwickler einen Objektpool durch
malloc+placement new, vergaß jedoch, den Destruktor beim Zurückgeben des Objekts in den Pool aufzurufen. Infolgedessen wurden Ressourcen (Systemdeskriptoren innerhalb der Objekte) nicht freigegeben, was zu Lecks und "Einfrieren" von Servern führte.
Geschichte
In einem Projekt zur Serialisierung von Binärdaten wurde ein Puffer und
placement newverwendet, um Objekte vor Ort zu dekodieren. Es wurde jedoch versäumt, den Speicher vor der Platzierung mit Nullen zu initialisieren, was zu einem Lesen nicht initialisierter Daten und seltsamen Bugs bei der Arbeit mit POD-Strukturen führte.
Geschichte
Eines der Module migrierte zur Platzierung von Objektarrays mit
placement newinnerhalb eines zuvor reservierten Blocks. Nach dem Hinzufügen neuer Mitglieder mit nicht-trivialen Destruktoren im Inneren der Klasse traten Programmabstürze auf — vergessen, dass jetzt der Destruktor für jedes Element beim Bereinigen explizit aufgerufen werden muss, was zuvor nicht erforderlich war.