Чтение онлайн

на главную - закладки

Жанры

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

Майерс Скотт

Шрифт:

Убрать обработчик new, то есть передать нулевой указатель set_new_handler. Если обработчик не установлен, то operator new сразу возбудит исключение при неудачной попытке выделить память.

Возбудить исключение типа bad_alloc либо некоторого типа, унаследованного от bad_alloc. Такие исключения не перехватывает operator new, поэтому они распространяются до того места, где была запрошена память.

Не возвращать управление – обычно вызвав abort или exit.

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

Иногда

обработать ошибки при выделении памяти можно и другими способами, зависящими от класса распределяемого объекта:

class X {

public:

static void outOfMemory;

...

};

class Y {

public:

static void outOfMemory;

...

};

X *p1 = new X; // если выделить память не удалось,

// вызвать X::outOfMemory

Y *p2 = new Y; // если выделить память не удалось,

// вызвать Y::outOfMemory

С++ не поддерживает специфичных для класса обработчиков new, но он и не нуждается в них. Вы можете реализовать такое поведение самостоятельно. Для этого просто в каждом классе определяете собственную версию set_new_handler и operator new. Определенная в классе функция set_new_handler класса позволит пользователям задать обработчик new для класса (точно так же, как обычный set_new_handler устанавливает глобальный обработчик new). Принадлежащий классу operator new гарантирует, что при выделении памяти для объектов этого класса вместо глобального обработчика new будет использован тот, что определен в данном классе.

Предположим, вы хотите обработать ошибки выделения памяти для класса Widget. Понадобится функция, которая будет вызываться, когда operator new не может выделить достаточно памяти для объекта Widget, поэтому вы объявляете статический член типа new_handler для хранения указателя на обработчик new для класса. Тогда Widget будет выглядеть примерно так:

class Widget {

public:

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

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

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

Дракон - не подарок

Суббота Светлана
2. Королевская академия Драко
Фантастика:
фэнтези
6.74
рейтинг книги
Дракон - не подарок

Бастард Императора. Том 8

Орлов Андрей Юрьевич
8. Бастард Императора
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Бастард Императора. Том 8

Чужая дочь

Зика Натаэль
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Чужая дочь

Эра Мангуста. Том 2

Третьяков Андрей
2. Рос: Мангуст
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Эра Мангуста. Том 2

Идеальный мир для Лекаря 14

Сапфир Олег
14. Лекарь
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 14

Один на миллион. Трилогия

Земляной Андрей Борисович
Один на миллион
Фантастика:
боевая фантастика
8.95
рейтинг книги
Один на миллион. Трилогия

Помещицы из будущего

Порохня Анна
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Помещицы из будущего

Шлейф сандала

Лерн Анна
Фантастика:
фэнтези
6.00
рейтинг книги
Шлейф сандала

Черный маг императора 2

Герда Александр
2. Черный маг императора
Фантастика:
юмористическая фантастика
попаданцы
аниме
6.00
рейтинг книги
Черный маг императора 2

Император

Рави Ивар
7. Прометей
Фантастика:
фэнтези
7.11
рейтинг книги
Император

Бандит 2

Щепетнов Евгений Владимирович
2. Петр Синельников
Фантастика:
боевая фантастика
5.73
рейтинг книги
Бандит 2

На границе империй. Том 9. Часть 2

INDIGO
15. Фортуна дама переменчивая
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 9. Часть 2

Князь Серединного мира

Земляной Андрей Борисович
4. Страж
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Князь Серединного мира

Чайлдфри

Тоцка Тала
Любовные романы:
современные любовные романы
6.51
рейтинг книги
Чайлдфри