Что происходит в C ++, когда вызывается оператор удаления? - PullRequest
2 голосов
/ 11 августа 2010

В C ++ я понимаю, что оператор delete при использовании с массивом уничтожает его, освобождая используемую память.Но что произойдет, когда это будет сделано?

Я подумал, что моя программа просто выделит соответствующую часть кучи, освобождаемой для повторного использования, и продолжит работу.

Но я заметил, что первый элемент массива также имеет значение null, а остальные элементы остаются без изменений.Какой цели это служит?

int * nums = new int[3];
nums[0] = 1;
nums[1] = 2;

cout << "nums[0]: " << *nums << endl;
cout << "nums[1]: " << *(nums+1) << endl;

delete [] nums;

cout << "nums[0]: " << *nums << endl;
cout << "nums[1]: " << *(nums+1) << endl;

Ответы [ 3 ]

19 голосов
/ 11 августа 2010

При вызове delete[] происходят две вещи:

  1. Если массив относится к типу, имеющему нетривиальный деструктор, деструктор вызывается для каждого элемента в массиве в обратном порядке
  2. Память, занятая массивом, освобождается

Доступ к памяти, занятой массивом после вызова delete, приводит к неопределенному поведению (то есть может произойти все, что угодно - данные могут все еще оставаться, или ваша программа может аварийно завершить работу, когда вы пытаетесь ее прочитать, или что-то еще может произойти гораздо хуже).

1 голос
/ 11 августа 2010

Причины, по которым он равен NULL, связаны с реализацией кучи.

Некоторые возможные причины - использование пространства для отслеживания свободного пространства.Возможно, он используется как указатель на следующий свободный блок.Возможно, он используется для записи размера свободного блока.Это может быть запись в некоторый серийный номер для нового / удаления отслеживания отладки.

Это может быть просто запись NULL, потому что это похоже на это.

0 голосов
/ 11 августа 2010

Всякий раз, когда кто-то говорит int* nums = new int[3], система времени выполнения обязана хранить количество объектов, 3, в месте, которое можно получить, зная только указатель, nums. Компилятор может использовать любую технику, которую захочет, но есть две популярные.

Код, сгенерированный nums = new int[3], может хранить число 3 в статическом ассоциативном массиве, где указатель nums используется в качестве ключа поиска, а число 3 является ассоциированным значением. Код, сгенерированный delete[] nums, ищет указатель в ассоциативном массиве, извлекает связанный size_t, а затем удаляет запись из ассоциативного массива.

Код, сгенерированный nums = new int[3], может выделить дополнительный размер памяти (size_t) байтов (возможно, плюс несколько байтов выравнивания) и поместить значение 3 непосредственно перед первым int объектом. Тогда delete[] nums найдет 3, посмотрев на фиксированное смещение перед первым int объектом (то есть до *num), и освободит память, начиная с начала выделения (то есть блока память начинает фиксированное смещение до *nums).

Ни одна техника не идеальна. Вот несколько компромиссов.

Метод ассоциативного массива медленнее, но безопаснее: если кто-то забудет [] при освобождении массива вещей, (a) запись в ассоциативном массиве будет утечкой, и (b) только первый объект в массив будет разрушен. Это может быть или не быть серьезной проблемой, но, по крайней мере, это может не привести к сбою приложения.

Техника перераспределения быстрее, но более опасна: если кто-то скажет delete nums, где он должен был сказать delete[] nums, адрес, который передается оператору delete(void* nums), не будет правильным распределением кучи - это будет по крайней мере sizeof(size_t) байт после правильного выделения кучи. Это, вероятно, повредит кучу. - C ++ FAQs

...