Перегрузка new и delete
Большинство классов содержит операции по распределению и освобождению памяти. Иногда для обеспечения эффективности или надежности требуется более изощренное использование памяти, чем то, которое предоставляется с помощью простого, вызова операторов new и delete.
Оператор new имеет следующий общий вид:
:: opt new размещениеopt тип инициализаторopt
Здесь optобозначает необязательные (optional) части. Вот некоторые примеры:
::new char[10]; //настаивает на глобальном new new(buff) Х(а); //вызов с buff используя X: :X(a)
До сих пор для выделения свободной памяти мы использовали глобальный оператор new (). Система неявно предоставляет аргумент sizeof (тип} для этой функции. Вот прототип функции:
void* operator new(size_t size) ;
Операторы new и delete могут быть перегружены. Это свойство предоставляет механизм, позволяющий пользователю манипулировать свободной памятью. Например, в традиционном программировании на С для доступа к свободной памяти используется malloc (), она возвращает void* указатель на выделенную память. В этой схеме память освобождается с помощью функции free () из stdlib.h. Используем перегрузку операторов new и delete, чтобы позволить объекту Х управлять свободной памятью традиционным для С образом.
#include <stdlib.h> //определены malloc() и free ()
class X { public:
void* operator new(size_t size)
{ return (malloc(size)); }
void operator delete(void* ptr) { free(ptr); }
X(unsigned size) { new(size); }
~X( ) { delete(this); }
. . . . .
};
В этом примере класс X предоставляет перегруженные формы new () и delete (). Если класс перегружает operator new (), глобальный оператор по прежнему доступен с помощью оператора разрешения области видимости : :.
Одна из причин по которой перегружаются эти операторы состоит в стремлении придать им дополнительную семантику, например, обеспечение диагностической информации или устойчивости к сбоям. Кроме того, класс может обеспечивать более эффективную схему распределения памяти чем та, которую предоставляет система.
Синтаксис размещения (placement) предоставляет разделенный запятыми список аргументов, используемый для выбора перегруженного оператора new () с соответствующей сигнатурой. Эти дополнительные аргументы часто применяются для того, чтобы поместить создаваемый объект по конкретному адресу. Такая форма оператора new использует заголовочный файл new.h.
В файле over_new.cpp
//Синтаксис размещения и перегруженный new
#include <iostream.h>
#include <new.h>
char* buf1 = new char[1000];//вместо свободной памяти
char* buf2 = new char[1000];
class object { public:
. . . . .
private:
. . . . .
};
int main ()
{
object *p=new(buf1) object; // размещение в buf1
object *q=new(buf2) object; // размещение в buf2
. . . . .
}
Синтаксис размещения позволяет пользователю иметь произвольную сигнатуру для перегруженного оператора new. Эта сигнатура отличается от аргументов инициализатора, используемых в вызове new, выбирающем соответствующий конструктор.
Оператор delete бывает двух видов. Он может иметь следующие сигнатуры:
void operator delete(void* p) ;
void operator delete(void* p, size_t);
Первая сигнатура не заботится о количестве байт, возвращаемых оператором delete. В этом случае программист поставляет код, предоставляющий это значение. Вторая сигнатура включает аргумент size_t, передаваемый вызову delete. Он передается компилятору как размер объекта, на который указывает р. В каждом классе только одна форма delete может быть задана как статическая функция-член.
В файле new.h имеется указатель _new_handler на функцию, которая вызывает обработчик ошибок для оператора new. Если память исчерпана, указатель _new_handler используется для вызова системной процедуры. С помощью set_new_handler () пользователь может указать явную процедуру <<недостаточ-но памяти>>, которая заменит системную. Мы возвратимся к эти вопросам в разделе 11.2, «Использование signal.h», на стр. 315, когда будем обсуждать исключения, обработку ошибок и корректность программ.
В файле new_hdlr.cpp
//Простая отказоустойчивость с применением _new_handler
#include <new.h>
#include <stdlib.h> //для выхода
void heap_exhausted()//пользовательский
//обработчик ошибок
{
cerr « "КУЧА ИСЧЕРПАНА" « endl;
exit(1);
}
int main()
{
set_new_handler(heap_exhausted) ;
..... //истощение памяти как heap_exhausted()
}
Функции-члены new () и delete () всегда неявно статические. Функция new () вызывается до того, как объект существует и, следовательно, у него еще нет this. Функция delete() вызывается деструктором при уничтожении объекта.