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

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

Жанры

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

Майерс Скотт

Шрифт:

// указатель

освободить память, на которую указывает rawMemory

;

}

Версия этой функции, являющаяся членом класса, также проста, за исключением того, что нужно проверить размер того, что вы собираетесь освобождать. Предполагая, что оператор new, определенный в классе, передает запрос на выделение «неправильного» количества байтов глобальному::operator new, вы также должны передать информацию о «неверном» размере функции::operator delete:

class Base { //
то же, что и раньше, но добавлено

public: // объявление operator delete

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

static void operator delete(void *rawMemory, std::size_t size) throw;

...

};

void Base::operator delete(void *rawMemory, std::size_t size) throw

{

if(rawMemory == 0) return; // проверка на нулевой указатель

if(size != sizeof(Base)) { // если размер «неверный»,

::operator delete(rawMemory); // вызвать стандартный оператор

return; // delete для обработки запроса

}

освободить память, на которую указывает rawMemory

;

return;

}

Интересно, что значение типа size_t, которое C++ передает оператору delete, может быть неправильным, если удаляется объект, производный от класса, в котором нет виртуального деструктора. Одного этого уже достаточно, чтобы требовать от базового класса наличия виртуального деструктора, но в правиле 7 описана и другая, более существенная причина. Пока просто отметьте, что если вы опустили виртуальный деструктор в базовом классе, то функция operator delete может работать неправильно.

Что следует помнить

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

• Оператор delete не должен ничего делать при передаче ему нулевого указателя. Версии оператора delete уровня класса должны обрабатывать запросы на освобождение блоков, которые больше, чем ожидается.

Правило 52: Если вы написали оператор new с размещением, напишите и соответствующий оператор delete

Операторы new и delete с размещением встречаются в C++ не слишком часто, поэтому в том, что вы с ними не знакомы, нет ничего страшного. Вспомните (правила 16 и 17), что когда вы пишете такое выражение new:

Widget *pw = new Widget;

то вызываются две функции: оператор new, чтобы выделить память, и конструктор Widget по умолчанию.

Предположим, что первый вызов завершился успешно, а второй возбудил исключение. В этом случае необходимо

отменить выделение памяти, выполненное на шаге 1. В противном случае мы получим утечку памяти. Пользовательский код не может освободить память, потому что конструктор Widget возбудил исключение и pw ничего так и не было присвоено. Следовательно, пользователь так и не получил указатель на память, которая должна быть освобождена. Поэтому ответственность за отмену шага 1 возлагается на систему времени исполнения C++.

Исполняющая система рада бы вызвать оператор delete, соответствующий использованному на шаге 1 оператору new, но сделать это может лишь тогда, когда знает, какой именно вариант оператора delete – а их много – нужно вызвать. Это не проблема, если вы пользуетесь формами new и delete с обычными сигнатурами, потому что обычный оператор new:

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

соответствует обычному оператору delete:

void operator delete(void *rawMemory) throw; // обычная сигнатура

// в глобальной области

// видимости

void operator delete(void *rawMemory, // наиболее распространенная

std::size_t size) throw; // сигнатура в области

// видимости класса

Если вы пользуетесь только обычными формами new и delete, то исполняющая система легко найдет тот вариант delete, который знает, как отменить действие, выполненное оператором new. Проблема поиска правильного варианта delete возникает тогда, когда вы объявляете необычные формы оператора new – такие, которые принимают дополнительные параметры.

Например, предположим, что вы написали оператор new уровня класса, который требует задания потока ofstream, куда должна выводиться отладочная информация о выделении памяти, и вместе с ним написали также обычный оператор delete уровня класса:

class Widget {

public:

...

static void *operator new(std:size_t size, // необычная

std::ostream& logStream) // форма new

throw(std::bad_alloc);

static void operator delete(void *pMemory, // обычная

std:size_t size) throw; // форма delete

// уровня класса

...

};

Такое решение наверняка приведет к ошибкам, но чтобы понять, почему это так, придется познакомиться с некоторыми терминами.

Функция operator new, принимающая дополнительные параметры (помимо обязательного аргумента size_t), называется оператором new с размещением или размещающим оператором new (placement new). Приведенный выше оператор new как раз и является таковым. Особенно полезным бывает размещающий оператор new, для которого вторым аргументом служит указатель на область памяти, где объект должен быть сконструирован. Этот оператор new выглядит так:

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

Эпоха Опустошителя. Том I

Павлов Вел
1. Вечное Ристалище
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Эпоха Опустошителя. Том I

Проблема майора Багирова

Майер Кристина
1. Спецназ
Любовные романы:
современные любовные романы
6.60
рейтинг книги
Проблема майора Багирова

Законы Рода. Том 13

Андрей Мельник
13. Граф Берестьев
Фантастика:
аниме
фэнтези
5.00
рейтинг книги
Законы Рода. Том 13

Газлайтер. Том 15

Володин Григорий Григорьевич
15. История Телепата
Фантастика:
боевая фантастика
попаданцы
5.00
рейтинг книги
Газлайтер. Том 15

О, Путник!

Арбеков Александр Анатольевич
1. Квинтет. Миры
Фантастика:
социально-философская фантастика
5.00
рейтинг книги
О, Путник!

Прометей: каменный век

Рави Ивар
1. Прометей
Фантастика:
альтернативная история
6.82
рейтинг книги
Прометей: каменный век

Её (мой) ребенок

Рам Янка
Любовные романы:
современные любовные романы
6.91
рейтинг книги
Её (мой) ребенок

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

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

Прометей: каменный век II

Рави Ивар
2. Прометей
Фантастика:
альтернативная история
7.40
рейтинг книги
Прометей: каменный век II

Цвет сверхдержавы - красный. Трилогия

Симонов Сергей
Цвет сверхдержавы - красный
Фантастика:
попаданцы
альтернативная история
8.06
рейтинг книги
Цвет сверхдержавы - красный. Трилогия

Болтливый мертвец

Фрай Макс
7. Лабиринты Ехо
Фантастика:
фэнтези
9.41
рейтинг книги
Болтливый мертвец

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

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

Истребители. Трилогия

Поселягин Владимир Геннадьевич
Фантастика:
альтернативная история
7.30
рейтинг книги
Истребители. Трилогия

Лишняя дочь

Nata Zzika
Любовные романы:
любовно-фантастические романы
8.22
рейтинг книги
Лишняя дочь