Вход/Регистрация
Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ
вернуться

Майерс Скотт

Шрифт:

static void *operator new(std::size_t size) throw(std::bad_alloc);

private:

static std::new_handler currentHandler;

};

Статические члены класса должны быть определены вне самого класса (если только они не константные целые – см. правило 2), поэтому:

std::new_handler Widget::currentHandler = 0; // инициализировать нулем

// в файле реализации класса

Функция set_new_handler в классе Widget сохранит переданный ей указатель и вернет тот указатель на функцию, действовавшую ранее. Так же поступает и стандартная версия set_new_handler:

static std::new_handler set_new_handler(std::new_handler p) throw

{

std::new_handler oldHandler = currentHandler;

currentHandler = p;

return oldHandler;

}

А вот что должен делать operator new из класса Widget.

1. Вызвать стандартный set_new_handler, указав в качестве параметра функцию-обработчик ошибок из класса Widget. В результате обработчик new из класса Widget будет установлен в качестве глобального.

2. Вызвать глобальный operator new для реального выделения памяти. Если произойдет ошибка, глобальный operator new вызовет обработчик new, принадлежащий Widget, поскольку эта функция была установлена в качестве глобального обработчика. Если это ни к чему не приведет, то глобальный operator new возбудит исключение bad_alloc. В этом случае operator new из класса Widget должен восстановить исходный обработчик new, а затем распространить исключение. Чтобы гарантировать, что исходный обработчик всегда восстанавливается, класс Widget трактует его как ресурс и следует совету правила 13 об использовании управляющих ресурсами объектов для предотвращения утечек.

3. Если глобальный operator new в состоянии выделить достаточно памяти для объекта Widget, то operator new класса Widget возвращает указатель на выделенную память. Деструктор объекта, самостоятельно управляющего глобальным обработчиком new, автоматически восстанавливает тот глобальный обработчик, который был установлен перед вызовом operator new класса Widget.

Теперь посмотрим, как все это выразить на C++. Начнем с класса, управляющего ресурсами, который не содержит ничего, кроме основных операций, диктуемых идиомой RAII: захват ресурса во время конструирования объекта и освобождение при его уничтожении (см. правило 13):

class NewHandlerHolder {

public:

explicit NewHandlerHolder(std::new_handler nh) // получить текущий

:handler(nh) {} // обработчик new

~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; // если выделить память не удалось,

  • Читать дальше
  • 1
  • ...
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: