Удаление указателя в С++

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

Я видел довольно много вопросов в SO об удалении указателей, но все они, похоже, связаны с удалением класса, а не с "простым" указателем (или каким бы правилом он ни был), здесь код я ' m пытается запустить:

#include <iostream>;

using namespace std;

int main() {
  int myVar,
      *myPointer;

  myVar = 8;
  myPointer = &myVar;

  cout << "delete-ing pointers " << endl;
  cout << "Memory address: " << myPointer << endl;

  // Seems I can't *just* delete it, as it triggers an error 
  delete myPointer;
  cout << "myPointer: " << myPointer << endl;
  // Error: a.out(14399) malloc: *** error for object 0x7fff61e537f4:
  // pointer being freed was not allocated
  // *** set a breakpoint in malloc_error_break to debug
  // Abort trap: 6

  // Using the new keyword befor deleting it works, but
  // does it really frees up the space? 
  myPointer = new int;
  delete myPointer;
  cout << "myPointer: " << myPointer << endl;
  // myPointer continues to store a memory address.

  // Using NULL before deleting it, seems to work. 
  myPointer = NULL;
  delete myPointer;
  cout << "myPointer: " << myPointer << endl;
  // myPointer returns 0.

}

Итак, мои вопросы:

  • Почему первый случай не будет работать? Кажется, наиболее простое использование для использования и удаления указателя? Ошибка говорит, что память не была выделена, но "cout" вернул адрес.
  • Во втором примере ошибка не запускается, но выполнение cout значения myPointer еще возвращает адрес памяти?
  • Действительно ли работает # 3? Кажется, для меня работает, указатель больше не хранит адрес, это правильный способ удаления указателя?

Извините за длинный вопрос, хотел сделать это как можно более ясным, а также повторить, у меня мало опыта в программировании, поэтому, если бы кто-то мог ответить на него с использованием вопросов непрофессионала, было бы очень полезно!

47
05 нояб. '12 в 1:02
источник поделиться
6 ответов

1 и 2

myVar = 8; //not dynamically allocated. Can't call delete on it.
myPointer = new int; //dynamically allocated, can call delete on it.

Первая переменная была выделена в стеке. Вы можете вызывать удаление только в памяти, которую вы распределяете динамически (в куче) с помощью оператора new.

3.

  myPointer = NULL;
  delete myPointer;

Выше было ничего вообще. Вы ничего не освободили, поскольку указатель указал на NULL.


Не следует выполнять следующее:

myPointer = new int;
myPointer = NULL; //leaked memory, no pointer to above int
delete myPointer; //no point at all

Вы указали его в NULL, оставив пропущенную память (новый, выделенный вами). Вы должны освободить память, на которую вы указывали. Нет никакого способа получить доступ к выделенному new int больше, следовательно, утечка памяти.


Правильный способ:

myPointer = new int;
delete myPointer; //freed memory
myPointer = NULL; //pointed dangling ptr to NULL

Лучший способ:

Если вы используете С++, не используйте необработанные указатели. Используйте интеллектуальные указатели, которые могут обрабатывать эти вещи для вас с небольшими накладными расходами. С++ 11 поставляется с несколько.

101
05 нояб. '12 в 1:06
источник

Я считаю, что вы не совсем понимаете, как работают указатели.
Когда у вас есть указатель, указывающий на какую-то память, вы должны понимать три разных вещи:
- указатель (память) указывает "то, что указано"
- этот адрес памяти
- не все указатели должны удалить свою память: вам нужно только удалить память, которая была динамически распределена (используется оператор new).

Представьте себе:

int *ptr = new int; 
// ptr has the address of the memory.
// at this point, the actual memory doesn't have anything.
*ptr = 8;
// you're assigning the integer 8 into that memory.
delete ptr;
// you are only deleting the memory.
// at this point the pointer still has the same memory address (as you could
//   notice from your 2nd test) but what inside that memory is gone!

Когда вы сделали

ptr = NULL;
// you didn't delete the memory
// you're only saying that this pointer is now pointing to "nowhere".
// the memory that was pointed by this pointer is now lost.

С++ позволяет попробовать delete указатель, указывающий на null, но на самом деле ничего не делает, просто не дает никакой ошибки.

11
05 нояб. '12 в 3:00
источник

Указатели похожи на обычные переменные, поскольку их не нужно удалять. Они удаляются из памяти в конце выполнения функций и/или в конце программы.

Однако вы можете использовать указатели для выделения "блока" памяти, например, следующим образом:

int *some_integers = new int[20000]

Это позволит выделить пространство памяти для 20000 целых чисел. Полезно, потому что Stack имеет ограниченный размер, и вы можете захотеть с большой нагрузкой "ints" без ошибки.

Всякий раз, когда вы вызываете new, вы должны "удалить" в конце своей программы, потому что в противном случае вы получите утечку памяти, а некоторая выделенная память никогда не будет возвращена для других программ. Для этого:

delete [] some_integers;

Надеюсь, что это поможет.

10
05 нояб. '12 в 1:15
источник

В С++ существует правило, для каждого нового существует delete.

  • Почему первый случай не работает? Кажется, наиболее простое использование для использования и удаления указателя? Ошибка говорит, что память не была выделена, но "cout" вернул адрес.

new никогда не вызывается. Таким образом, адрес, который печатает cout, является адресом ячейки памяти myVar или значением, присвоенным myPointer в этом случае. Написав:

myPointer = &myVar;

вы говорите:

myPointer = Адрес, где хранятся данные в myVar

  1. Во втором примере ошибка не запускается, но выполнение cout значения myPointer все еще возвращает адрес памяти?

Он возвращает адрес, указывающий на удаленную ячейку памяти. Потому что сначала вы создаете указатель и назначаете его значение myPointer, а затем вы его удаляете, третий вы его печатаете. Поэтому, если вы не назначили другое значение myPointer, удаленный адрес останется.

  1. Действительно ли работает # 3? Кажется, для меня работает, указатель больше не хранит адрес, это правильный способ удаления указателя?

NULL равно 0, вы удаляете 0, поэтому ничего не удаляете. И логично, что он печатает 0, потому что вы сделали:

myPointer = NULL;

который равен:

myPointer = 0;
7
05 нояб. '12 в 1:08
источник
  • Вы пытаетесь удалить переменную, выделенную в стеке. Вы не можете этого сделать.
  • Удаление указателя фактически не уничтожает указатель, а только занятая память возвращается обратно в ОС. Вы можете получить доступ к нему до тех пор, пока память не будет использоваться для другой переменной или каким-либо другим способом. Поэтому рекомендуется удалить указатель на NULL (0) после удаления.
  • Удаление указателя NULL ничего не удаляет.
4
05 нояб. '12 в 1:11
источник
int value, *ptr;

value = 8;
ptr = &value;
// ptr points to value, which lives on a stack frame.
// you are not responsible for managing its lifetime.

ptr = new int;
delete ptr;
// yes this is the normal way to manage the lifetime of
// dynamically allocated memory, you new'ed it, you delete it.

ptr = nullptr;
delete ptr;
// this is illogical, essentially you are saying delete nothing.
1
05 нояб. '12 в 1:15
источник

Посмотрите другие вопросы по меткам или Задайте вопрос