Язык программирования C++ от Страуструпа

       

Указание размещения


По умолчанию операция 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, выбирается согласно правилам сопоставления параметров ($$R.13.2). Все функции 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);             // освобождение памяти

}

Заметим, что явных вызовов деструкторов, как и глобальных функций размещения специального назначения, следует, по возможности, избегать. Бывают случаи, когда обойтись без них трудно, но новичок должен трижды подумать, прежде чем использовать явный вызов деструктора, и должен сначала посоветоваться с более опытным коллегой.



Содержание раздела