2010-08-11 2 views
1

В C++ я понимаю, что оператор delete при использовании с массивом «уничтожает» его, освобождая используемую память. Но что происходит, когда это делается?В 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; 
+1

Вызов указателя на удаленный объект или массив - это UB. – strager

+2

Для неопределенного поведения нет цели, ни рифмы, ни разума. –

+3

@ Ханс: Мистер Роджерс не согласился: «Неопределенное поведение» рифмуется с «не будет ли вы моим соседом» ;-) –

ответ

19

Две вещи происходят, когда delete[] называется:

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

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

+0

+1 для четкого и краткого ответа :-). –

+0

Будет ли программа отслеживать выделенную память при изменении указателя на динамически распределенную память? например, если я увеличиваю указатель, после выделения памяти ему с помощью «нового», будет ли использоваться оператор «удалить», чтобы освободить исходный блок правильно? – ozmo

+0

@ozmo Нет, не будет. Вы можете удалить только указатели, которые вы выделили. @James, «может произойти что-то еще хуже» - хуже было бы (обычный случай), когда вы все равно сможете получить доступ к данным, но он изменился на что-то другое - например, «launchNuke = pCountry-> clearAndPresentDanger». – kibibu

1

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

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

Он может просто написать NULL, потому что он чувствует себя так.

+0

Я все еще задавался вопросом, что такое рифма или причина этого неопределенного поведения, так что это тоже было полезно, спасибо. – ozmo

0

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

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

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

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

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^