Полезное:
Как сделать разговор полезным и приятным
Как сделать объемную звезду своими руками
Как сделать то, что делать не хочется?
Как сделать погремушку
Как сделать так чтобы женщины сами знакомились с вами
Как сделать идею коммерческой
Как сделать хорошую растяжку ног?
Как сделать наш разум здоровым?
Как сделать, чтобы люди обманывали меньше
Вопрос 4. Как сделать так, чтобы вас уважали и ценили?
Как сделать лучше себе и другим людям
Как сделать свидание интересным?
Категории:
АрхитектураАстрономияБиологияГеографияГеологияИнформатикаИскусствоИсторияКулинарияКультураМаркетингМатематикаМедицинаМенеджментОхрана трудаПравоПроизводствоПсихологияРелигияСоциологияСпортТехникаФизикаФилософияХимияЭкологияЭкономикаЭлектроника
|
Перегрузка операций new и delete
Чтобы обеспечить альтернативные варианты управления памятью, можно определять собственные варианты операций new и new[] для выделения динамической памяти под объект и массив объектов соответственно, а также операции delete и delete [] для ее освобождения. Эти функции-операции должны соответствовать следующим правилам: • им не требуется передавать параметр типа класса; • первым параметром функциям new и new[] должен передаваться размер объекта типа s1ze_t (это тип, возвращаемый операцией sizeof, он определяется в заголовочном файле <stddef.h>); при вызове он передается в функции неявным образом; • они должны определяться с типом возвращаемого значения void*, даже если return возвращает указатель на другие типы (чаще всего на класс); • операция delete должна иметь тип возврата void и первый аргумент типа void*; • операции выделения и освобождения памяти являются статическими элементами класса. Поведение перегруженных операций должно соответствовать действиям, выполняемым ими по умолчанию. Для операции new это означает, что она должна возвращать правильное значение, корректно обрабатывать запрос на выделение памяти нулевого размера и порождать исключение при невозможности выполнения запроса. Для операции delete следует соблюдать условие, что удаление нулевого указателя должно быть безопасным, поэтому внутри операции необходима проверка указателя на нуль и отсутствие каких-либо действий в случае равенства. Стандартные операции выделения и освобождения памяти могут использоваться в области действия класса наряду с перегруженными (с помощью операции доступа к области видимости:: для объектов этого класса и непосредственно — для любых других). Перегрузка операции выделения памяти применяется для экономии памяти, повышения быстродействия программы или для размещения данных в некоторой конкретной области. Например, пусть описывается loiacc, содержащий указатель на некоторый объект: class Obj {...}: class pObjj private: Obj *p: }: При выделении памяти под объект типа pObj с помощью стандартной операции new pObj *р = new pObj: фактическое количество байтов будет превышать sizeof(pObj), поскольку new обычно записывает в начало выделяемой области ее размер (для того чтобы правильно отрабатывала операция delete): Для небольших объектов эти накладные расходы могут оказаться весьма значительными. Для экономии памяти можно написать собственную операцию new класса pObj, которая будет выделять большой блок памяти, а затем размещать в нем указатели на Obj. Для этого в объект pObj вводится статическое поле headOf Free, в котором хранится указатель на первую свободную ячейку блока для размещения очередного объекта. Неиспользуемые ячейки связываются в список. Чтобы не занимать память под поле связи, используется объединение (union), с помощью которого одна и та же ячейка используется либо для размещения указателя на объект, либо для связи со следующей свободной ячейкой: class pObj{ public: static void * operator new(size_t size): private: union{ Obj *p: // Указатель на объект pObj *next: // Указатель на следующую свободную ячейку }: static const int BLOCK__SIZE:// Размер блока // Заголовок списка свободных ячеек: static pObj *headOfFree: }: void * pObj::operator new(size_t size){ // Перенаправить запросы неверного количества памяти // стандартной операции new: if (size!= sizeof(pObj)) return::operator new(size); pObj *p = headOfFree; // Указатель на первую свободную ячейку // Переместить указатель списка свободных ячеек: if (р) headOfFree = р -> next: // Если свободной памяти нет. выделяем очередной блок: else { pObj *newblock = static__cast<pObj*>^ (::operator new(BLOCK__SIZE * sizeof(pObj))): // Bee ячейки свободны, кроме первой (она будет // занята), связываем их: for (int i - 1: i< BLOCKJIZE - 1: ++i) newblock[i].next = &newblock[i + 1 ]: newblock[BLOCK__SIZE - l].next = 0: // Устанавливаем начало списка свободных ячеек: headOfFree = &newblock[l]: р = newblock: } return p; / / Возвращаем указатель на выделенную память } Перегруженная операция new наследуется, поэтому она вызывается для производных объектов. Если их размер не соответствует размеру базового (а так, скорее всего, и есть), это может вызвать проблемы. Чтобы их избежать, в начале операции проверяется соответствие размеров. Если размер объекта не равен тому, для которого перегружена операция new, запрос на выделение памяти передается стандартной операции new. В программе, использующей класс pObj, должна присутствовать инициализация его статических полей: pObj *pObj::headOfFree: // Устанавливается в О по умолчанию const int pObj::BLOCK_SIZE = 1024: Как видно из этого примера, помимо экономии памяти достигается еще и высокое быстродействие, ведь в большинстве случаев выделение памяти сводится к нескольким простым операторам. Естественно, что если операция new перегружена, то же самое должно быть выполнено и для операции delete (например, в нашем случае стандартная операция delete не найдет в начале объекта верной информации о его размерах, что приведет к неопределенному поведению программы). В рассмотренном примере операция delete должна добавлять освобожденную ячейку памяти к списку свободных ячеек: void pObj::operator delete(void * ObjToDie. size^t size){ i f (ObjToDie *== 0) return: i f (size!= sizeof(pObj)){ ^ Здесь использовано явное преобразование типа с помощью операции staticcast. ::operator delete(ObjToDie): return: } pObj *p = stat1c_cast<p0bj*>(0bjToDie); p->next = headOfFree; headOfFree = p; } В операции delete выполнена проверка соответствия размеров объектов, аналогичная приведенной в операции new. Date: 2016-07-25; view: 482; Нарушение авторских прав |