~NewHandlerHolder() // освободить его
{ std::set_new_handler(handler);}
private:
std::new_handler handler; // запомнить его
NewHandlerHolder(const NewHandlerHolder&); // предотвратить
NewHandlerHolder& // копирование
operator=(const NewHandlerHolder&); // (см. правило 14)
};
Это делает реализацию оператора new для Widget совсем простой:
void Widget::orerator new(std::size_td size) throw(std::bad_aloc)
{
NewHandlerHolder // установить обработчик
h(std::set_new_handler(currentHandler)); // new из класса Widget
return ::operator new(size); // выделить память или
// возбудить исключение
} // восстановить глобальный
// обработчик new
Пользователи класса Widget применяют эти средства следующим образом:
void outOfMem(); // объявление функции, которую нужно
// вызвать, если выделить память
// для Widget не удается
Widget::set_new_handler(outOfmem); // установка outOfMem в качестве
// обработчика new для Widget
Widget *pw1 = new Widget; // если выделить память не удалось,
// вызывается outOfMem
std::string *ps = new std::string; // если выделить память не удалось,
// вызывается глобальный обработчик new
// (если есть)
Widget::set_new_handler(0); // отменяет обработчик new
Widget *pw1 = new Widget; // если выделить память не удалось,
// сразу же возбуждается исключение (никакого
// обработчика new сейчас нет)
Код, реализующий эту схему, один и тот же (независимо от класса), поэтому разумно было бы повторно использовать его в других местах. Простой способ сделать это – создать «присоединяемый» базовый класс, то есть базовый класс, который предназначен для того, чтобы подклассы могли унаследовать одно-единственное средство, в данном случае способность устанавливать специфичный для класса обработчик new. Затем превратите базовый класс в шаблон, чтобы каждый производный класс мог получать разные копии данных.
При таком подходе принадлежащая базовому классу часть позволяет подклассам наследовать необходимые им функции set_new_handler и operator new, а шаблонная часть гарантирует, что у каждого подкласса будет собственный член данных currentHandler. Звучит сложновато, но код выглядит обнадеживающе знакомым. Фактически единственным отличием является то, что теперь он доступен любому классу:
template // «присоединяемый» базовый класс для
class NewHandlerSupport { // поддержки специфичной для класса
public: // функции set_new_handler
static std::new_handler set_new_handler(std::new_handler p) throw();
static void *operator new(std::size_t size) throw(std::bad_alloc);
... // другие версии оператора new – см. правило 52
private:
static std::new_handler currentHandler;
};
template
std::new_handler
NewHandlerSupport::set_new_handler(std::new_handler p) throw()
{
std::new_handler oldHandler = currentHandler;
currentHandler = p;
return oldHandler;
}
template
void *NewHandlerSupport::operator(std::size_t size)
throw(std::bad_alloc)
{
NewHandlerHolder h(std::set_new_handler(currentHandler);
return ::operator new(size);
}
// currentHandler в любом классе инициализируется значением null
template
std::new_handler NewHandlerSupport::currentHandler = 0;
С этим шаблоном класса добавление поддержки set_new_handler к Widget очень просто: Widget просто наследуется от NewHandlerSupport. (Это может показаться экстравагантным, но ниже я подробно объясню, что здесь происходит.)
class Widget: public NewHandlerSupport {
... // как раньше, но без декларации
}; // set_new_handler или operator new
Это все, что нужно сделать в классе Widget, чтобы предоставить специфичный для класса обработчик set_new_handler.
Но может быть, вас беспокоит тот факт, что Widget наследует классу New-HandlerSupport? Если так, то ваше беспокойство усилится, когда вы заметите, что NewHandlerSupport никогда не использует свой параметр типа T. Он не нуждается в нем. Единственное, что нам нужно, – это отдельная копия NewHandlerSupport, а точнее его статический член currentHandler для каждого класса, производного от NewHandlerSupport. Параметр шаблона T просто отличает один подкласс от другого. Механизм шаблонов автоматически генерирует копию currentHandler для каждого типа T, для которого он конкретизируется.
Читать дальше
Конец ознакомительного отрывка
Купить книгу