Информационный сайт

 

Реклама
bulletinsite.net -> Книги на сайте -> Программисту -> Мизрохи С.В. -> "Turbo Pascal и объектно-ориентированное программирование" -> 21

Turbo Pascal и объектно-ориентированное программирование - Мизрохи С.В.

Мизрохи С.В. Turbo Pascal и объектно-ориентированное программирование — М.: Финансы и статистика , 1992. — 192 c.
ISBN 5-279-00903-2
Скачать (прямая ссылка): efektispolzc2000.djvu
Предыдущая << 1 .. 15 16 17 18 19 20 < 21 > 22 23 24 25 26 27 .. 105 >> Следующая

Il нулевого указателя. удаляем память, на которую указывает rawMemory
Управление памятью
return;
} . .
Версия этой функции, определенной как член класса, тоже проста; единственный нюанс заключается в том, чтобы проверять размер удаляемого объекта. Если operator new передает запросы памяти «неправильного» размера функции : : operator new, то запросы на удаление объектов «неправильного» размера следует передавать функции : : operator delete:
class Base { Il Тот же класс, только добавлен оператор delete, public:
static void * operator new(size_t size) ;
static void operator delete(void *rawMemory, size_t size); «* • »
};
void Base::operator delete(void *rawMemory, size_t size) {
if (rawMemory == 0) return; Il Проверить нулевой указатель.
if (size sizeof (Base) ) { Il Если размер "не тот", пусть запрос
: : operator delete (rawMemory); Il обработает стандартный return; . Il оператор delete.
}
удаляем память, на которую указывает rawMemory ' •
return;
}
Правила для операторов new и delete (и их аналогов для массивов) не особенно обременительны, но придерживаться Pix следует. Если написанные вами функции выделения памяти поддерживают функции-обработчики new и корректно обрабатывают запросы нулевого размера, то это практически все, что требуется, а если эти функции высвобождения памяти умеют работать с нулевыми указателями, то вам осталось совсем немного - добавить поддержку наследования для функций-членов.
Правило 9. Старайтесь не скрывать «нормальную» форму new
Определение имени во внутренней области видимости скрывает это имя во всех внешних областях, так что если функция f определена и в глобальной области видимости, и в области видимости класса, то функция-член скроет глобальную функцию:
void f () ; // Глобальная функция.
class X { ' ,
public :
void f(); Il Функция-члєн.
};
X х;
f(); // Вызывает глобальную f.
X.f() ; Il ВЫЗЫВаеТ X : :f.
Іравило 9
I
^^^Ш Такое поведение в нормальной ситуации не приведет к путанице, поскольку ЩРЩобальпые функции и функции-члены обычно вызываются с использованием разных синтаксических форм. Однако, если добавить к классу оператор new, требующий дополнительных аргументов, результат может вас неприятно удивить:
class X {
public:
VOid f ( ) ;
Il Оператор new, которому необходимо указать функцию-обработчик, static void * operator new(size_t size, new_handler p) ;
};
void. specialErrorHandler () ; Il Определение в другом месте.
X *pxl - new (specialErrorHandler) X; // Вызывает X: :operator new. X *рх2 = new X; Il Ошибка!
Определив функцию по имени operator new внутри этого класса, вы, сами того не заметив, заблокируете доступ к «нормальной» форме оператора new. Почему так происходит, обсуждается в правиле 50. Здесь же нас больше интересует, как можно этого избежать.
Одно из решений проблемы - написать для класса оператор new, поддерживающий вызов «нормальной» функции. Если он делает то же самое, что и глобальная функция, это может быть эффективно и изящно реализовано с помощью встраиваемой функции:
class X { ' '
public: * . і. ¦
void f() ;
static void * operator new(size_t size, new_handler p) ; static void * operator new(size_t size) { return ::operator new(size); }
};
X *pxl = new (specialErrorHandler) X; Il Вызывает X: :operator
// new(size_t, new_handler ) . X* px2 = new X; Il Вызывает X: :operator new(size_t) .
В качестве альтернативы для каждого дополнительного аргумента оператора new можно задать значение по умолчанию (см. правило 24):
class X {
Public:
void f ( ) ;
static
void * operator new(size_t size, new_handler p - 0) ;
Il Заметьте: у p есть значение по умолчанию.
};
X *pxl = new (specialErrorHandler) X; // Нормально. X* рх2 = new X; //И это тоже.
В любом случае, если вы позднее решите модифицировать поведение «нормальной» функции new, все, что вам необходимо будет сделать, - это переписать ее. После Перекомпоновки вы сразу добьетесь желаемого поведения в месте вызова функции new.
If) Управление памятью
Memory for Airplane Object
Правило 10. Если вы написали оператор new, напишите и оператор delete
Давайте ненадолго вернемся к основам. Почему иногда возникает желание написать свою собственную версию operator new или operator delete?
Чаще всего побудительной причиной является стремление повысить эффективность. Версии operator new или operator delete по умолчанию идеально подходят для использования в общих целях, но их гибкость неизбежно приводит к мысли об улучшении функциональности в частных случаях. Это особенно верно для приложений, которые динамически размещают большое количество маленьких объектов.
В качестве примера давайте рассмотрим класс, призванный описывать самолеты, причем класс Airplane содержит.только указатели на объекты, действительно описывающие самолеты (прием, обсуждаемый в правиле 34):
class AirplaneRep {... }; // Реализация объекта "самолет", class Airplane {
public: "* J '
і
private: 1 , . ,
AirplaneRep *rep; Il Указатель на реализацию.
};
Объект Airplane не очень большой и содержит только один указатель. (Как объясняется в правиле 14, если в классе объявлены виртуальные функции, он может неявно содержать еще один указатель.) При выделении памяти объекту Airplane посредством вызова new вы, весьма вероятно, получите больше памяти, чем нужно для хранения этого указателя (или пары указателей). Причина такого поведения заключается в необходимости поддержания соответствия между операторами new и delete.
Предыдущая << 1 .. 15 16 17 18 19 20 < 21 > 22 23 24 25 26 27 .. 105 >> Следующая
Реклама
Авторские права © 2009 AdsNet. Все права защищены.
Rambler's Top100