Вызов delete для переменной, размещенной в стеке - PullRequest
52 голосов
/ 14 января 2009

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

Например:

   int nAmount;
   delete &nAmount;

или

class sample
{
public:
    sample();
    ~sample() { delete &nAmount;}
    int nAmount;
}

Ответы [ 11 ]

97 голосов
/ 14 января 2009

Нет , небезопасно вызывать delete для переменной, выделенной из стека. Вы должны звонить delete только на вещи, созданные new.

  • Для каждого malloc или calloc должен быть ровно один free.
  • Для каждого new должен быть ровно один delete.
  • Для каждого new[] должен быть ровно один delete[].
  • Для каждого выделения стека не должно быть явного освобождения или удаления. Деструктор вызывается автоматически, где это применимо.

Как правило, вы не можете смешивать и сочетать любые из них, например, нет free -ing или delete[] -ing new объекта. Это приводит к неопределенному поведению.

46 голосов
/ 14 января 2009

Хорошо, давайте попробуем:

jeremy@jeremy-desktop:~$ echo 'main() { int a; delete &a; }' > test.cpp
jeremy@jeremy-desktop:~$ g++ -o test test.cpp
jeremy@jeremy-desktop:~$ ./test
Segmentation fault

Так что, видимо, это совсем не безопасно.

14 голосов
/ 14 января 2009

Имейте в виду, что когда вы выделяете блок памяти, используя new (или malloc в этом отношении), фактический выделенный блок памяти будет больше, чем вы запрашивали. Блок памяти также будет содержать некоторую бухгалтерскую информацию, так что когда вы освобождаете блок, его можно легко вернуть обратно в пул свободных мест и, возможно, объединить со смежными свободными блоками.

Когда вы пытаетесь освободить память, которую вы не получили от новой, этой бухгалтерской информации не будет, но система будет работать так, как она есть, и результаты будут непредсказуемыми (обычно плохими). ​​

10 голосов
/ 20 сентября 2012

Да, это неопределенное поведение: передача на delete всего, что не пришло с new, является UB:

Стандарт C ++, раздел 3.7.3.2.3: Значение первого аргумента, передаваемого одной из функций освобождения, предоставляемых в стандартной библиотеке, может быть значением указателя null; если так, и если функция освобождения предоставлена ​​в стандартной библиотеке, вызов функции освобождения не имеет никакого эффекта. В противном случае значение, предоставляемое operator delete(void*) в стандартной библиотеке, должно быть одним из значений, возвращаемых предыдущим вызовом operator new(std::size_t) или operator new(std::size_t, const std::nothrow_t&) в стандартной библиотеке.

Последствия неопределенного поведения, ну, в общем, неопределенные. «Ничего не происходит» так же важно, как и все остальное. Однако обычно это «сразу ничего не происходит»: освобождение недопустимого блока памяти может иметь серьезные последствия при последующих вызовах распределителя.

7 голосов
/ 17 мая 2011

Немного поиграв с g ++ 4.4 в windows, я получил очень интересные результаты:

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

  2. Наличие класса с методом с delete this успешно удаляет объект, если он расположен в куче, но не если он расположен в стеке (если он находится в стеке, ничего не происходит). 1010 *

5 голосов
/ 20 сентября 2012

Никто не может знать, что происходит. Это вызывает неопределенное поведение, поэтому буквально все может произойти. Не делай этого.

4 голосов
/ 14 января 2009

Нет, Память, выделенная с помощью new, должна быть удалена с помощью оператора delete и то, что выделено с помощью malloc, должно быть удалено с помощью free. И нет необходимости освобождать переменную, расположенную в стеке.

3 голосов
/ 20 сентября 2012

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

1 голос
/ 14 января 2009

здесь память распределяется с использованием стека, поэтому нет необходимости удалять ее извне, но если вы динамически добавляли все

как int * a = new int ()

тогда вы должны удалить, а не удалить & a (сам по себе является указателем), поскольку память выделяется из свободного хранилища.

0 голосов
/ 20 сентября 2012

Это UB, потому что вы не должны вызывать delete для элемента, который не был динамически выделен с новым. Это так просто.

...