Программирование. Принципы и практика использования C++ Исправленное издание, стр. 226
double* p4 = new double[5];for (int i = 0; i<5; ++i) p4[i] = i;Теперь указатель
p4double0.01.02.03.04.0Как обычно, мы должны избегать неинициализированных объектов и следить за тем, чтобы они получили значения до того, как будут использованы. Компиляторы часто имеют режим отладки, в котором они по умолчанию инициализируют все переменные предсказуемой величиной (обычно нулем). Это значит, что, когда вы отключаете режим отладки, чтобы отправить программу заказчику, запускаете оптимизатор или просто компилируете программу на другой машине, программа, содержащая неинициализированные переменные, может внезапно перестать работать правильно. Не используйте неинициализированные переменные. Если класс
XX* px1 = new X; // один объект класса Х, инициализированный // по умолчаниюX* px2 = new X[17]; // 17 объектов класса Х, инициализированных // по умолчаниюЕсли класс
YY* py1 = new Y; // ошибка: нет конструктора по умолчаниюY* py2 = new Y[17]; // ошибка: нет конструктора по умолчаниюY* py3 = new Y(13); // OK: инициализирован адресом объекта Y(13)17.4.5. Нулевой указатель
Если в вашем распоряжении нет другого указателя, которым можно было бы инициализировать ваш указатель, используйте
0double* p0 = 0; // нулевой указательУказатель, которому присвоен нуль, называют нулевым (null pointer). Корректность указателя (т.е. ссылается ли он на что-либо) часто проверяется с помощью сравнения его с нулем. Рассмотрим пример.
if (p0 != 0) // проверка корректности указателя p0Этот тест неидеален, поскольку указатель
p0deleteifif (p0) // проверка корректности указателя p0; эквивалентно p0!=0
p0Нулевой указатель следует использовать тогда, когда некий указатель то ссылается на какой-нибудь объект, то нет. Эта ситуация встречается реже, чем можно себе представить; подумайте: если у вас нет объекта, на который можно установить указатель, то зачем вам определять сам указатель? Почему бы не подождать, пока не будет создан объект?
17.4.6. Освобождение свободной памяти
Оператор
newdouble* calc(int res_size, int max) // утечка памяти{ double* p = new double[max]; double* res = new double[res_size]; // используем указатель p для вычисления результатов // и записи их в массив res return res;}double* r = calc(100,1000);В соответствии с этой программой каждый вызов функции
calc()doublepcalc(100,1000)doubleОператор, возвращающий освобождающую память, называется
deletedeletenewdouble* calc(int res_size, int max) // за использование памяти, выделенной для массива res, // несет ответственность вызывающий модуль{ double* p = new double[max]; double* res = new double[res_size]; // используем указатель p для вычисления результатов и их // записи в res delete[ ] p; // эта память больше не нужна: освобождаем ее return res;} double* r = calc(100,1000); // используем указатель r delete[ ] r; // эта память больше не нужна: освобождаем ееМежду прочим, этот пример демонстрирует одну из основных причин использования свободной памяти: мы можем создавать объекты в функции и передавать их обратно в вызывающий модуль.
Оператор
delete