placement new to szczególna forma operatora new w C++. Pozwala na umieszczanie obiektu pod wskazanym adresem w już przydzielonym obszarze pamięci. Zwykle jest używany do ręcznego zarządzania pamięcią, leży u podstaw działania alokatorów, puli obiektów i serializacji do stałych buforów.
Składnia:
#include <new> void* memory = malloc(sizeof(MyClass)); MyClass* obj = new (memory) MyClass(args...); // wywołuje konstruktor pod adresem memory
Tutaj pamięć jest przydzielana osobno (na przykład przez malloc lub alokator), a następnie konstruktor klasy jest wywoływany w tej pamięci. Nie zapomnij jawnie wywołać destruktora:
obj->~MyClass(); free(memory);
Zalety:
Czy ten sam blok pamięci może być używany do umieszczania kilku obiektów w kolejności za pomocą 'placement new', i jakie to wywołuje konsekwencje?
Częsty błędny odpowiedź — można umieszczać nowe obiekty w pamięci, nie dbając o poprzedni stan. W rzeczywistości, jeśli w tej samej przestrzeni pamięci umieszcza się nowy obiekt na starym bez wywołania jego destruktora, dojdzie do wycieku zasobów, a wywołanie destruktora później spowoduje UB.
Przykład:
void* place = malloc(sizeof(A)); A* a = new (place) A(); B* b = new (place) B(); // obiekt A nie został zniszczony! UB!
Historia
W systemie o wysokiej wydajności programista zrealizował pulę obiektów za pomocą
malloc+placement new, ale zapomniał wywołać destruktor przy zwracaniu obiektu do puli. W rezultacie zasoby (systemowe deskryptory wewnątrz obiektów) nie były zwalniane, co prowadziło do wycieków i "zawieszania" serwerów.
Historia
W projekcie do serializacji danych binarnych użyto bufora i
placement new, aby dekodować obiekty na miejscu. Zapomniano jednak zainicjować pamięć zerami przed umieszczeniem, co doprowadziło do odczytu nieinicjowanych danych i dziwnych błędów podczas pracy z strukturami POD.
Historia
Jeden z modułów migrował na umieszczanie tablic obiektów za pomocą
placement newwewnątrz wcześniej przydzielonego bloku. Po dodaniu nowych członków do klasy z nietrywialnymi destruktorami wystąpiły nagłe zakończenia programu — zapomniano, że teraz należy jawnie wywoływać destruktor dla każdego elementu przy czyszczeniu, co wcześniej nie było wymagane.