Если определяются собственные глобальные функции operator new()
и operator delete()
, они должны резервировать и освобождать память так или иначе. Даже если эти функции определяются для использования специализированной системы резервирования памяти, может иметь смысл (для проверки) иметь способность резервировать память тем же способом, что и обычная реализация.
В этом случае можно использовать функции malloc()
и free()
, унаследованные языком С++ от языка С. Они определяются в заголовке cstdlib
.
Функция malloc()
получает параметр типа size_t
, задающий количество резервируемых байтов. Она возвращает указатель на зарезервированную область памяти или значение 0, если зарезервировать память не удалось. Функция free()
получает параметр типа void*
, являющийся копией указателя, возвращенного функцией malloc()
, и возвращает занятую память операционной системе. Вызов free(0)
не делает ничего.
Вот простейший код функций operator new()
и operator delete()
:
void *operator new(size_t size) {
if (void *mem = malloc(size))
return mem;
else
throw bad_alloc();
}
void operator delete(void *mem) noexcept { free(mem); }
Для других версий функции operator new()
и operator delete()
код аналогичен.
Упражнение 19.1. Напишите собственную версию функции operator new(size_t)
, используя функцию malloc()
, и версию функции operator delete(void*)
, используя функцию free()
.
Упражнение 19.2. По умолчанию класс allocator
использует функцию operator new()
для резервирования места и функцию operator delete()
для ее освобождения. Перекомпилируйте и повторно запустите программу StrVec
(см. раздел 13.5), используя собственные версии функций из предыдущего упражнения.
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
создает объект, но не резервирует память.