По умолчанию операция new создает указанный ей объект в свободной памяти. Как быть, если надо разместить объект в определенном месте? Этого можно добиться переопределением операции размещения. Рассмотрим простой класс:
class X { // ... public: X(int); // ... };
Объект можно разместить в любом месте, если ввести в функцию размещения дополнительные параметры:
// операция размещения в указанном месте: void* operator new(size_t, void* p) { return p; }
и задав эти параметры для операции new следующим образом:
char buffer[sizeof(X)];
void f(int i) { X* p = new(buffer) X(i); // разместить X в buffer // ... }
Функция operator new(), используемая операцией new, выбирается согласно правилам сопоставления параметров. Все функции operator new() должны иметь первым параметром size_t. Задаваемый этим параметром размер неявно передается операцией new.
Определенная нами функция operator new() с задаваемым размещением является самой простой из функций подобного рода. Можно привести другой пример функции размещения, выделяющей память из некоторой заданной области:
class Arena { // ... virtual void* alloc(size_t) = 0; virtual void free(void*) = 0; };
void operator new(size_t sz, Arena* a) { return a.alloc(sz); }
Теперь можно отводить память для объектов произвольных типов из различных областей (Arena):
extern Arena* Persistent; // постоянная память extern Arena* Shared; // разделяемая память
void g(int i) { X* p = new(Persistent) X(i); // X в постоянной памяти X* q = new(Shared) X(i); // X в разделяемой памяти // ... }
Если мы помещаем объект в область памяти, которая непосредственно не управляется стандартными функциями распределения свободной памяти, то надо позаботиться о правильном уничтожении объекта. Основным средством здесь является явный вызов деструктора:
void h(X* p) { p->~X(); // вызов деструктора Persistent->free(p); // освобождение памяти }
Заметим, что явных вызовов деструкторов, как и глобальных функций размещения специального назначения, следует, по возможности, избегать. Бывают случаи, когда обойтись без них трудно, но новичок должен трижды подумать, прежде чем использовать явный вызов деструктора, и должен сначала посоветоваться с более опытным коллегой.