Удаление вложенной структуры с пустыми указателями в качестве членов? - PullRequest
1 голос
/ 23 июля 2010

У меня есть следующий класс:

class Stack {
  struct Link {
    void* data;
    Link* next;
    void initialize(void* dat, Link* nxt);
  }* head;
public:
  void initialize();
  void push(void* dat);
  void* peek();
  void* pop();
  void cleanup();
};

Метод pop:

void* Stack::pop() {
  if(head == 0) return 0;
  void* result = head->data;
  Link* oldHead = head;
  head = head->next;
  delete oldHead;
  return result;
}

oldHead - это указатель на struct Link, который имеет пустотууказатель в качестве члена.Итак, удаляя oldHead, я неявно удаляю этот пустой указатель, верно?

Я читаю Thinking in C ++ Брюса Эккеля, и он говорит, что удаление пустых указателей не очищает вещи должным образом, потому что delete должен знать тип указателя.

Этот код неявно удаляет указатель void data, поэтому: Может кто-то объяснить, почему этот (неявный) способ удаления указателя void отличается от удаления с помощью delete <void pointer>?

Ответы [ 4 ]

2 голосов
/ 23 июля 2010

Ваша терминология вызывает двусмысленность, но позвольте мне объяснить.Допустим, у вас есть:

struct foo
{
    void* bar;
};

Всякий раз, когда foo заканчивает свое время жизни, bar просто перестает существовать.Так что если у вас есть:

{
    foo f = { new int; }
}

Вы просочились, так как new int никогда не удаляется.Аналогично, когда вы делаете:

{
    foo* f = new foo;
    f->bar = new int;
    delete f;
}

Вы все еще просочились, так как, когда запускается delete f, вы просто заканчиваете время жизни того, на что указывает f (точно так же, как это произошло автоматически выше)ergo bar просто перестает существовать и new int не удаляется.

Подводя итог, когда заканчивается время жизни объекта, delete - это , а не , который вызывается для членов, которыеуказатель.

Таким образом, когда вы вызываете delete для Link, это та же самая ситуация, что и bar в foo выше: вы удаляете память для Link, вызывая data впрекратить существование, но не удалять то, на что оно указывает.

0 голосов
/ 23 июля 2010

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

#include <iostream>

struct foo
{
    ~foo() { std::cout << "important work" << std::endl; }
};

int main()
{
    foo *f = new foo;

    void *v = f;

    delete v;
}

Если вы запустите пример кода выше, вы увидите, что деструктор никогда не вызывается.

0 голосов
/ 23 июля 2010

«Я неявно удаляю этот пустой указатель, верно?»

Ну, вы удаляете сам указатель при удалении oldHead. Вы не удаляете и не освобождаете его target , что, как вам кажется, нужно, и то, что происходит, когда вы вызываете delete для указателя.

(Чтобы понять, почему это так, учтите, что вы можете определить структуру с указателем void*, который указывает на что-то вне структуры. Вы не хотели бы, чтобы цель была освобождена только потому, что структура была удалена. )

0 голосов
/ 23 июля 2010

При удалении Link это пустое * пространство памяти не удаляется.Вам необходимо определить деструктор, который удаляет выделенную память.Каждому новому нужно одно удаление.Примером этого для Link-struct может быть добавление деструктора, удаляющего data.Если ваше предположение будет правильным, то next также будет удалено, что приведет к удалению всего связанного списка, что будет ужасным поведением.

Вызов delete для указателя вызовет деструктор указанногопечатать.Если этот тип не имеет деструктора, такой деструктор не будет вызван.Это тот случай, когда указатель void не имеет деструктора.В случае наследования деструктор всегда должен быть виртуальным, чтобы у самого глубокого класса в иерархии был вызван деструктор.Память будет правильно освобождена, даже если вы приведете свои указатели к неправильным типам - просто деструктор будет вызван неправильно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...