19.1.2. Размещающий оператор new

Хотя функции operator new() и operator delete() предназначены для использования выражениями new, они являются обычными библиотечными функциями. Поэтому обычный код вполне может вызвать их непосредственно.

В прежних версиях языка (до того, как класс allocator (см. раздел 12.2.2) стал частью библиотеки), когда необходимо было отделить резервирование от инициализации, использовались функции operator new() и operator delete(). Эти функции ведут себя аналогично функциям-членам allocate() и deallocate() класса allocator — резервируют и освобождают память, но не создают и не удаляют объекты.

В отличие от класса allocator, нет функции construct(), позволяющей создавать объекты в памяти, зарезервированной функцией operator new(). Вместо этого для создания объекта используется размещающий оператор new (placement new) (см. раздел 12.1.2). Как уже упоминалось, эта форма оператора new предоставляет дополнительную информацию функции резервирования. Размещающий оператор new можно использовать для передачи адреса области. Тогда выражения размещающего оператора new будут иметь следующую форму:

new (адрес_области) тип

new (адрес_области) тип (инициализаторы)

new (адрес_области) тип [размер]

new (адрес_области) тип [размер] { список инициализации }

где адрес_области является указателем, а инициализаторы представляют собой разделяемый запятыми список инициализаторов (возможно, пустой), используемый для создания вновь зарезервированного объекта.

Будучи вызванным с адресом, но без других аргументов, размещающий оператор new использует вызов operator new(size_t, void*) для "резервирования" памяти. Эта версия функции operator new() не допускает переопределения (см. раздел 19.1.1). Она не резервирует память, а просто возвращает свой аргумент указателя. Затем обычное выражение new заканчивает свою работу инициализацией объекта по данному адресу. В действительности размещающий оператор new позволяет создать объект в заданной адресом предварительно зарезервированной области памяти.

При передаче одного аргумента, являющегося указателем, выражение размещающего оператора new создает объект, но не резервирует память.

Хотя существует несколько способов использования размещающего оператора new, он похож на функцию-член construct() класса allocator, но с одним важным отличием. Передаваемый функции construct() указатель должен указывать на область, зарезервированную тем же объектом класса allocator. Указатель, передаваемый размещающему оператору new, не обязан указывать на область памяти, зарезервированной функцией operator new(). Как будет продемонстрировано в разделе 19.6, переданный выражению размещающего оператора new указатель даже не обязан указывать на динамическую память.

Явный вызов деструктора

Подобно тому, как размещающий оператор new является низкоуровневой альтернативой функции-члену allocate() класса allocator, явный вызов деструктора аналогичен вызову функции destroy().

Вызов деструктора происходит таким же образом, как и любой другой функции-члена объекта: через указатель или ссылку на объект:

string *sp = new string("a value"); // резервирует и инициализирует

                                    // строку

sp->~string();

Здесь деструктор вызывается непосредственно. Для получения объекта, на который указывает указатель sp, используется оператор стрелки. Затем происходит вызов деструктора, имя которого совпадает с именем типа, но с предваряющим знаком тильды (~).

Подобно вызову функции destroy(), вызов деструктора освобождает заданный объект, но не освобождает область, в которой располагается этот объект. При желании эту область можно использовать многократно.

Вызов деструктора удаляет объект, но не освобождает память.