Можно ли использовать "удалить это" для удаления текущего объекта?

Я пишу связанный список, и я хочу, чтобы деструктор структуры (структура Node) просто удалил сам себя и не имел побочных эффектов. Я хочу, чтобы деструктор моего списка итеративно вызывал деструктор Node сам по себе (временно сохраняя следующий узел), например так:

//my list class has first and last pointers
//and my nodes each have a pointer to the previous and next
//node
DoublyLinkedList::~DoublyLinkedList
{
    Node *temp = first();

    while (temp->next() != NULL)
    {
        delete temp;
        temp = temp->next();
    }
}

Так что это будет мой деструктор Node:

Node::~Node
{
   delete this;
}

Это приемлемо, особенно в этом контексте?

8 ответов

Если вызывается деструктор Node, то он уже находится в процессе удаления. Таким образом, удаление не имеет смысла в вашем деструкторе Node.

Также это неправильно:

while (temp->next() != NULL)
{
     delete temp;
     temp = temp->next();
}

Вместо этого вы должны получить temp->next() в переменной temp. В противном случае вы получаете доступ к удаленной памяти.

Итак, больше похоже на это:

DoublyLinkedList::~DoublyLinkedList
{
  Node *temp = first();
  while (temp != NULL)
  {
       Node *temp2 = temp->next();
       delete temp;
       temp = temp2;
  }
}

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

delete temp;
temp = temp->next();

Если вы хотите рекурсивно удалить структуру, вы хотите что-то вроде этого:

DoublyLinkedList::~DoublyLinkedList
{
    Node *temp = first();
    delete temp;
}

Node::~Node
{
   if(this->next() != NULL) delete this->next();
}

Нет не должен delete this от деструктора. Деструктор вызывается из-за оператора удаления (или выходит из области видимости), и это, скорее всего, приведет к некоторому сбою.

У вас также есть пара проблем в деструкторе DoublyLinkedList. Во-первых, вы удаляете temp, а затем получаете доступ к temp после ее удаления. Во-вторых, код фактически не удалит последний элемент в связанном списке.

Прежде всего: я действительно, очень надеюсь, что это домашнее задание, назначенное вам для того, чтобы понять двусвязный список. В противном случае нет причин использовать это вместо std::list, С этим из пути:

Нет, delete this в дторе всегда неправильно, так как дтор вызывается, когда this находится в состоянии удаления.

Кроме того, в то время как

delete temp;
temp = temp->next();

кстати может сработать, это уж точно неправильно, т.к. там, где вы пытаетесь получить доступ temp->next(), temp уже удален, поэтому вы должны вызвать функцию-член на нем. Это вызывает так называемое "неопределенное поведение". (Короче говоря: он может делать то, что вы хотите, но он также может терпеть неудачу всегда или время от времени, или только когда пятница, 13-е, сталкивается с новолунием. Это также может вызвать на вас очень неприятных носовых демонов.)

Обратите внимание, что вы можете решить обе проблемы, удалив следующий узел в dtor вашего узла:

Node::~Node()
{
   delete next();
}

Таким образом, ваш список dtor тоже становится очень простым:

DoublyLinkedList::~DoublyLinkedList()
{
    delete first();
}

Мне кажется, для этого и были придуманы dtors, поэтому, за исключением того факта, что в наше время никто больше не должен писать свои собственные типы связанных списков, мне кажется, что это решение C++ для вашей проблемы.

Удалить это; вызовет деструктор текущего объекта. В этом случае, если вы звоните, удалите это; в деструкторе, то деструктор будет бесконечно вызываться до крушения.

Оба никогда не должны быть сделаны.

это

DoublyLinkedList::~DoublyLinkedList
{
    Node *temp = first();
    while (temp->next() != NULL)
    {
        delete temp;
        temp = temp->next();
    }
}

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

DoublyLinkedList::~DoublyLinkedList
{
    Node *temp = first();
    while( temp != NULL)
    {
        Node* next = temp->next();
        delete temp;
        temp = next;
    }
}

призвание delete this приведет к так называемой двойной свободе, которая также вызовет неопределенное поведение. Деструктор должен вызывать delete только для переменных-указателей, но не для this, призвание delete this разумно использовать другие методы для освобождения текущего объекта, но не от деструктора.

Код выше вызовет Node::~Node() дважды. (в "delete temp" и в Node::~Node())

Node::~Node() не должен вызывать "delete this" (иначе ваша программа потерпит крах)

пс. Цикл while в вашем коде не будет работать. Будет разыменован неверный указатель. Сначала вы должны скопировать значение temp->next, а затем уничтожить указатель temp.

В общем, деструктор должен просто беспокоиться об удалении (или освобождении, если вы используете C или malloc) любой памяти, выделенной специально для вашего объекта. Удаление указателя на ваш объект всегда будет управляться ОС, и вам не нужно беспокоиться об этом.

Следует иметь в виду, что при создании вы сначала создаете объект (когда поток управления входит в тело конструктора), а затем объекты внутри; для уничтожения вы должны сделать это в обратном порядке, потому что, если вы сначала удалите внешний объект, у вас не будет доступа к внутренним указателям для их удаления. Вместо этого вы удаляете внутренние объекты, используя деструктор, затем ОС управляет фактическим освобождением памяти, когда поток управления выпадает из деструктора.

Кстати, то же самое происходит с подклассами: если у вас есть класс A и класс B: public A, то когда вы делаете новый B(), сначала выполняется конструктор A, затем конструктор B; При уничтожении сначала выполняется деструктор B, а затем A. Я вполне уверен, что вам не нужно беспокоиться об этом, хотя - C++ позаботится об этом за вас. Поэтому не пытайтесь найти способ вызвать delete в суперклассе.

Другие вопросы по тегам