Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Перегрузка и управление памятью

Поиск

В программах, написанных на ANSI С, используются функции malloc() и free() вместе с им подобными библиотечными функциями для выделения и освобождения блоков памяти в куче.

в про­граммах, написанных на C++, используются операторы new и delete.

На самом деле, в большинстве реализа­ций C++ new и delete скрыто реализуются вызовами функций mallocO и freeO. Поэтому некоторые програм­мисты на C++ не видят для себя особой разницы между способами управления памятью в ANSI Сив C++.

Однако подобное предположение таит в себе опасность, поскольку new и delete на самом деле операторы, а не функции. Как операторы, new и delete могут перегружаться с целью задания новых возможностей управ­ления памятью для объектов класса.

С помощью перегрузки new и delete вы можете получить полный кон­троль над операциями выделения памяти объектам.

ПРЕДУПРЕЖДЕНИЕ

Никогда не вызывайте функцию free() для освобождения памяти, выделяемой с помощью оператора new, и никогда не вызывайте mallocO для выделения памяти, освобождаемой позднее с помощью delete. Использование способов управления распределением памяти ANSI С и C++ вперемежку может в некоторых случаях сработать, однако программа, скорее всего, будет завершаться аварийно, если new и delete перегружаются в классе или если Borland изменит внутреннюю реализацию этих операторов в будущих версиях компилятора.

Перегрузка оператора new

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

Для перегрузки new следует использовать прототип функции вида

void * operator new(size_t size);.

В даль­нейшем обращения к оператору new для выделения памяти объектам класса будут перенаправлены перегруженнойфункции.

Функция должна возвращать адрес области памяти, выделенной объекту. Если необходимо­го свободного пространства нет, функция должна возвращать null (нуль).

В листинге 4.7 приводится простой, но полный пример перегрузки оператора new для выделения памяти объектам. Вместо кучи программа запоминает их в глобальном буфере.

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

ЗАМЕЧАНИЕ

В строке 6 OVERNEW.CPP приводится команда #pragma warn -aus. Она предписывает компилятору выключить предупреждение о том, что в программе не используются переменные, объявленные исключительно в демонстрационных целях.

Функция перегрузки оператора new, объявленная в строке 13 и реализованная в строках 38-48, проверяет наличие пространства в глобальном буфере. Если его нет, функция возвращает 0, что является основанием для возвращения оператором new значения null. (В программе не проверяется это условие, но, конечно, вы должны проверять его в реальных приложениях.) Если свободное пространство есть, глобальный индекс уве­личивается на размер запрашиваемой памяти, который передается функции в параметре size. Затем функция возвращает адрес выделяемого участка памяти.

Листинг 4.7. OVERNEW.CPP (перегрузка new)

//4_7.cpp

#include <iostream.h>

#include <conio.h>

// Следующая директива "pragma" выключает //предупреждение компилятора о том, что

// в программе объявляются и не используются //демонстрационные переменные

#pragma warn -aus

class BNew { private:

int x;

public:

BNew();

// Функция перегрузки оператора new

void * operator new(size_t size);

};

char buf[512]; int index=0;

main() {

cout << "\nCreating local instance";

BNew b1;

cout << "\nAllocating space via new";

BNew *b2 = new BNew;

BNew *b3 = new BNew;

BNew *b4 = new BNew;

BNew *b5 = new BNew;

getch();

return 0;

}

BNew::BNew()

{

cout << "\n constructor";

x = index;

}

void *BNew::operator new(size_t size)

{

cout << "\n lnside overloaded new. Size = "<< size;

if (index >= 512 - sizeof(BNew))

{getch();

return 0;}

else {

int k = index;

index += sizeof(BNew);

return &buf[k];

}}

Перегрузка delete

Оператор delete — обратная сторона медали распределения памяти.

Можно пере­грузить оператор delete для отслеживания удаления объектов, адресованных указателями.

Прототип функции перегрузки оператора delete должен иметь вид

void operator delete(void *p);

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

void operator delete(void *p, size_t size);

В соответствии с вторым объявлением C++ будет дополнительно передавать функции число байтов в уда­ляемом объекте.

Для добавления функции перегрузки оператора delete в класс BNew в модуле OVERNEW (листинг 4.7) объявить функцию-член в открытой секции класса:

void BNew::operator delete(void *p)

cout << "\nDeleting object at " «p;

Оператора вывода отображает адрес каждого удаляемого объекта.

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

также потребуется несколько операторов для удаления нескольких объектов. Вставьте следующие строки в функцию mainO непосредственно перед оператором return:

delete Ь2; delete ЬЗ; delete Ь4; delete Ь5;

//4_7А.cpp

#include <iostream.h>

#include <conio.h>

class BNew { private:

int x; public:

BNew();

void * operator new(size_t size);

void operator delete(void *p);

};

char buf[512]; int index=0;

main() {

clrscr();

cout << "\nCreating local instance";

BNew b1;

cout << "\nAllocating space via new";

BNew *b2 = new BNew;

BNew *b3 = new BNew;

BNew *b4 = new BNew;

BNew *b5 = new BNew;

delete b2;

delete b3;

getch();

return 0;

}

BNew::BNew()

{

cout << "\nlnside constructor";

x = index;

}

void *BNew::operator new(size_t size)

{

//cout << "\nlnside overloaded new. Size = "<< size;

//cout << "\n index = "<< index;

if (index >= (512 - sizeof(BNew)))

{getch();

return 0;}

else {

int k = index;

index += sizeof(BNew);

//cout << "\n k = "<< k;

return &buf[k];

}

}

void BNew::operator delete(void *p)

{

cout << "\n delete "<< p;

}

 

Этот пример приведен только для демонстрации, поскольку в полноценном при­ложении перегруженный оператор delete должен освобождать удаленные блоки памяти для последующего ис­пользования их перегруженным new.

ЗАМЕЧАНИЕ

Чтобы использовать средства управления памятью C + + для выделения пространства в куче для объектов, в которых перетружен оператор new, поставьте перед оператором двойное двоеточие. Например, и строке

BNew *х =::new BrandNew игнорируется перегруженный в объектах класса BNew оператор new. Аналогично,::delete служит для обращения к оператору delete, используемому по умолчанию.

Установка обработчика ошибок оператора new

Обычно, если new не может выполнить запрос выделения памяти, оператор возвращает null.

Для того что­бы изменить действия, предпринимаемые по умолчанию в этом случае, в C++ следует присвоить адрес функ­ции-обработчика ошибок указателю _new__handler, определенному следующим образом:

typedef void (*vfp)(void);

vfp _new_handler;

Использование typedef не обязательно, но оно облегчает чтение объявления. Функция-обработчик ошибок ничего не возвращает и не имеет аргументов, она устанавливается с помощью вызова функции set_new_handler(), прототип которой содержится в файле NEW.H:

vfp set_new_handler(vfp);

Обработчик ошибок реализуется так же, как и обычная функция C++. Например, аварийно за­вершить программу с сообщением об ошибке нехватки памяти:

void memerr(void)

{

fputs("\n\nOut of memory\n", stderr);

exit(1);

}

Для того чтобы функция memerrO вызывалась в случае возникновения ошибок, связанных с нехваткой па­мяти, передайте адрес memerr функции set_new_handler() следующим образом;

set_new_handler(memerr);

ЗАМЕЧАНИЕ

Смотри также описание set_jiew_handler() в книге Освоение Borland C++. Энциклопедия функций.



Поделиться:


Последнее изменение этой страницы: 2016-08-01; просмотров: 283; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.191.171.86 (0.006 с.)