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

 

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

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

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

new_handler globalHandler = set_new_handler(0) ;
set_new_handler(globalHandler);
if '(globalHandler) (*globalHandler) () ;
else throw std::bad_alloc(); l
Трюк с обработкой запросов на 0 байт выглядит странным, как если бы это были запросы на 1 байт, но этот метод прост, законен и... работает.
Вас также может смутить то место в псевдокоде, где функция обработки ошибки установлена в ноль, а затем быстренько переустановлена в свое исходное состояние. К сожалению, не существует прямого способа непосредственного получения указателя на обработчик new, поетому, чтобы получить его, вам необходимо вызвать set_new_handler. Грубо, конечно, но зато эффективно.
В правиле 7 уже было сказано, что operator new содержит бесконечный цикл, и в приведенном выше коде этот цикл налицо: while (true) бесконечен так, что дальше некуда. Выбраться из него мы можем тогда, когда память будет успешно выделена или функция-обработчик new выполнит одно из действий, описанных в правиле 7: сделает доступным большее количество памяти, установит другой обработчик new, деинсталлирует обработчик new, сгенерирует исключение типа s t d: : bad_al 1ос или не вернет управление, завершив программу. Теперь вам должно быть понятно, почему обработчик new должен выполнить одно из этих действий. Если он этого не сделает, то цикл внутри оператора new никогда не закончится.
У оператора new есть свойство, которое многие упускают из виду: он наследуется производными классами. Это может приводить к некоторым осложнениям. Обратите внимание, что в псевдокоде оператора new, приведенном выше, функция пытается выделить size байтов (если s і zе не равно 0). Такое поведение вполне разумно, поскольку именно этот аргумент передан функции. Однако большинство версий операторов new для классов (включая ту, которую вы обнаружите в правиле 10) спроектировано только для конкретного класса, а не для класса со всеми его подклассами. То есть при наличии у класса определения функции operator new ее поведение практически всегда настраивается для работы с объектами размера sizeof (X) -не больше и не меньше. Из-за наследования, однако, оператор new базового класса будет вызван для выделения памяти объекту производного класса:
class Base {
public :
static void * operator new(size_t size);
};
class Derived: public Base { - . - } ;
Derived *p = new Derived;
Il Derived не объявляет operator new.
Il Вызов Base::operator new!
Правило 8
1 Имеются в виду невложенные классы. -
Прим. научного редактора.
Если оператор new для класса Base не был спроектирован для того, чтобы справляться с подобной ситуацией (вероятнее всего, так и есть), лучше всего перенести обязанность выделения «неправильного» количества памяти па стандартный оператор new следующим образом:
void * Base::operator new(size_t size) (
if (size != sizeof (Base) ) Il Если размер "не тот",
return ::operator new(size); Il пусть запрос обработает
Il стандартный оператор new. ... Il В противном случае обрабатываем запрос здесь.
}
«Постойте-ка! - скажете вы. - Вы забыли проверить не вполне типичный случай, когда size равен нулю!» На самом деле я об этом не забыл. Такая проверка здесь содержится, и встроена она в сравнение size с sizeof (Base). Пути стандарта С++ неисповедимы, и одно из подтверждений тому - соглашение, что все самостоятельные1 классы имеют ненулевой размер. По определению значене sizeof (Base) никогда не может быть равно нулю (даже если класс не содержит членов), поэтому, если size равен 0, запрос будет передан функции !operator new и она станет отвечать за адекватную обработку этого запроса. Если вы хотите управлять выделением памяти массивам для отдельных классов, вам потребуется реализовать родственную оператору new функцию - operator new [ ]. (Она обычно называется new для массивов, поскольку трудно понять, как следует произносить operator new [ ].) Если вы решите написать свой operator new [ ], помните, что вы отвечаете только за выделение неструктурированной памяти. С несуществующими объектами массива вы ничего делать не можете. В действительности вы даже не можете рассчитать, сколько объектов будет в массиве, так как вам неизвестен размер каждого объекта. В конце концов, operator new [ ], объявленный в базовом классе, может быть вызван с целью выделения памяти для массивов объектов производных классов, но такие объекты обычно больше по размерам, чем объекты базовых классов. Поэтому внутри Base: : operator new [ ] нельзя предполагать, что размер каждого объекта массива равен sizeof (Base), а количество объектов в массиве - значению выражения (запрошенное количество байтов)/sizeof (Base).
Вот и все правила, которым необходимо следовать, когда вы определяете operator new (и operator new [ ] ). Для оператора delete и его аналога для массивов - оператора delete [] все намного проще. С++ гарантирует безопасность Удаления нулевого объекта, поэтому вам также следует соблюдать эту гарантию. Приведем псевдокод для оператора delete:
void operator delete(void *rawMemory) {
if (rawMemory -~ 0) return; // Ничего не делаем при удалении
Предыдущая << 1 .. 14 15 16 17 18 19 < 20 > 21 22 23 24 25 26 .. 105 >> Следующая
Реклама
Авторские права © 2009 AdsNet. Все права защищены.
Rambler's Top100