Программирование. Принципы и практика использования C++ Исправленное издание, стр. 227
•
delete pnew•
delete[] pnewВыбор правильного варианта должен сделать программист.
int* p = new int(5);delete p; // отлично: p ссылается на объект, созданный оператором new // ...указатель здесь больше не используется...delete p; // ошибка: p ссылается на память, принадлежащую диспетчеру // свободной памятиВторая инструкция
delete p• Вы больше не ссылаетесь на объект, поэтому диспетчер свободной памяти может изменить внутреннюю структуру данных так, чтобы выполнить инструкцию
delete p• Диспетчер свободной памяти может повторно использовать память, на которую ссылался указатель
ppОбе проблемы встречаются в реальных программах; так что это не просто теоретические возможности.
Удаление нулевого указателя не приводит ни к каким последствиям (так как нулевой указатель не ссылается ни на один объект), поэтому эта операция безвредна. Рассмотрим пример.
int* p = 0;delete p; // отлично: никаких действий не нужноdelete p; // тоже хорошо (по-прежнему ничего делать не нужно)Зачем возиться с освобождением памяти? Разве компилятор сам не может понять, когда память нам больше не нужна, и освободить ее без вмешательства человека? Может. Такой механизм называется автоматической сборкой мусора (automatic garbage collection) или просто сборкой мусора (garbage collection). К сожалению, автоматическая сборка мусора недешевое удовольствие и не идеально подходит ко всем приложениям. Если вам действительно нужна автоматическая сборка мусора, можете встроить этот механизм в свою программу. Хорошие сборщики мусора доступны по адресу www.research.att.com/~bs/C++.html. Однако в этой книге мы предполагаем, что читатели сами разберутся со своим “мусором”, а мы покажем, как это сделать удобно и эффективно.
17.5. Деструкторы
Теперь мы знаем, как хранить элементы в векторе. Мы просто выделим достаточное количество свободной памяти и будем обращаться к ней с помощью указателя.
// очень упрощенный вектор, содержащий числа типа doubleclass vector { int sz; // размер double* elem; // указатель на элементыpublic: vector(int s) // конструктор :sz(s), // инициализация члена sz elem(new double[s]) // инициализация члена elem { for (int i=0; i<s; ++i) elem[i]=0; // инициализация // элементов } int size() const { return sz; } // текущий размер // ...};Итак, член
szvectorsize()newnewelemОбратите внимание на то, что мы инициализируем элементы их значением по умолчанию (
0.0vectorК сожалению, наш примитивный класс
vectornewdeletevoid f(int n){ vector v(n); // выделяем память для n чисел типа double // ...}После выхода из функции
f()vclean_up()vectorvoid f2(int n)