Во время выполнения обнаружение удаления памяти - PullRequest
2 голосов
/ 31 июля 2011

Код:

int *ptr = new int[10];
int *q = ptr;
delete q;

отлично работает без проблем (без ошибок времени выполнения).

Однако следующий код:

int *ptr = new int[10];
int *q = ptr;
q++;
delete q;

результатыво время выполнения ошибки.

Я использую Microsoft Visual Studio-8 и Win-7 в качестве платформы.

Я не могу понять, почему во втором случае возникает ошибка во время выполнения?

Ответы [ 4 ]

9 голосов
/ 31 июля 2011

Ваш код вызывает неопределенное поведение . Неопределенное поведение означает, что все может произойти, поведение не может быть определено. Программа работает просто по счастливой случайности, ее поведение не может быть объяснено.

В основном

Если вы выделяете динамическую память с помощью new, вы ДОЛЖНЫ использовать delete для ее освобождения.

Если вы выделяете динамическую память с помощью new[], вы ДОЛЖНЫ использовать delete[] для ее освобождения.

Передача любого адреса в delete, который не был возвращен new.
, является неопределенным поведением. Вот цитата из Стандарта.

Согласно C ++ 03 Standard § 3.7.4.2-3:

Если функция освобождения завершается выдачей исключения, поведение не определено. Значение первого аргумента, переданного функции освобождения, может быть значением нулевого указателя; если так, и если функция освобождения предоставлена ​​в стандартной библиотеке, вызов не имеет никакого эффекта. В противном случае предоставленное значение для оператора delete(void*) в стандартной библиотеке должно быть одно из значений, возвращаемых предыдущим вызовом оператора new(std::size_t) или operator new(std::size_t, const std::nothrow_-t&) в стандартной библиотеке, а значение, предоставляемое оператору delete[](void*) в стандартной библиотеке, должно быть одно из значений, возвращаемых предыдущим вызовом operator new[](std::size_t) или operator new[](std::size_t, const std::nothrow_t&) в стандартной библиотеке.

В C ++ лучше использовать RAII (SBRM) , используя Умные указатели вместо необработанных указателей, которые автоматически заботятся об освобождении памяти.

3 голосов
/ 31 июля 2011

Здесь есть две ошибки:

  1. Вы не можете delete указатель, который не был возвращен new.
  2. Вы не можете delete указатель, который был возвращен new[] - вам нужно использовать delete[].

Итак, первый фрагмент работает только по совпадению, и нет ошибки только потому, что вы используете примитивный тип. Если бы это был UDT, деструкторы не работали бы.

Кроме того, вы должны использовать контейнеры и умные указатели вместо raw new и delete.

1 голос
/ 31 июля 2011

Поскольку вы должны передать неизмененный результат удаления нового.Именно так все и работает, то есть контракт API new / delete.

0 голосов
/ 31 июля 2011

Поскольку вы изменили адрес, на который указывает q, а затем попытались удалить его.

Вам следует только когда-либо попытаться delete все, что new вернет вам.Все остальное - неопределенное поведение.

...