Пример деструктора C ++ - PullRequest
       13

Пример деструктора C ++

0 голосов
/ 31 января 2010

Мой C ++ немного ржавый, но я создал программу, которая переворачивает связанный список, и сейчас я пытаюсь написать для него подходящие деструкторы, но я не знаю точно, что уничтожать. Вот мои определения классов:

class LinkedList
{
    private:ListElement *start;
    public:LinkedList();
    public:void AddElement(int val);
    public:void PrintList();
    public:void InvertList();
};

class ListElement
{
    public:int value;
    public:ListElement * link;
    public:ListElement(int val);
    public:ListElement();
};


class Stack
{

private:ListElement ** stack;
private:int index;
public:Stack(int size);
public:void push(ListElement * le);
public:ListElement * pop();

};

Стек предназначен для того, чтобы перевернуть список. Тем не мение ... Как мне написать деструкторы для них? Я думал:

Для ListElement укажите значение 0 и ссылку 0 (NULL).

Для LinkedList просмотрите элементы и вызовите ListElementDestructor для всех из них.

Я не очень уверен в этом, потому что, как я понимаю, деструктор автоматически вызывает деструкторы объектов-членов, поэтому достаточно ли в этом случае только написания пустого деструктора для LinkedList? Я не знаю ... вот почему я спрашиваю

Для стека я не знаю ... указатели уже 0 (NULL) после инвертирования списка, потому что они все всплывают.

Я немного растерялся. Кто-нибудь может помочь? Заранее спасибо.

Ответы [ 3 ]

9 голосов
/ 31 января 2010

Вы уничтожаете вещи, которые нужно уничтожить. Если ваш класс создал объекты с использованием new, вам, вероятно, нужен деструктор, который удаляет их с помощью деструктора. Обратите внимание, что контейнеры, такие как LinkedList, должны содержать только те элементы, которые были выделены динамически или нет. Если вы смешиваете два или смешиваете оригиналы и копии, как я подозреваю, вы делаете, вам, вероятно, нужно использовать умные указатели или счетчики ссылок.

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

И в-третьих, могу ли я сказать, что ваш стиль C ++ не идиоматичен и для меня почти нечитабелен - создание C ++, похожего на Java, НЕ является хорошей идеей. Изменить на:

class LinkedList
{
    private:
       ListElement *start;
    public:
       LinkedList();
       void AddElement(int val);
       void PrintList();
       void InvertList();
};
1 голос
/ 31 января 2010

Класс LinkedList создает ListElements. Поэтому вам нужно выполнить цикл от начала до конца списка (если он не пустой) и:

delete currentElement;

В деструкторе LinkedList. Поскольку ListElement хранит значение в виде 'int', вам не нужно здесь освобождать память. Как ты и думал.

Опять же, нет необходимости освобождать память в деструкторе класса Stack. В общем удалите все что у вас новое! И пусть за работу отвечает один человек (класс)!

1 голос
/ 31 января 2010

Для ListElement задайте значение 0 и ссылку 0 (NULL).

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

Главное, в чем вы должны быть уверены, это то, что все элементы, выделенные в куче (т. Е. С использованием new), удаляются с помощью delete (или delete [] в случае массивов).

Для LinkedList просмотрите элементы и вызовите ListElementDestructor для всех из них.

Для объекта, размещенного в стеке, он автоматически вызывается, когда объект выходит из области видимости.
Для динамически размещаемого объекта (т. Е. Созданного с использованием new) деструктор вызывается, когда он удаляется с помощью delete. Другими словами, вам не нужно вызывать никаких деструкторов, поскольку они вызываются автоматически, если вы правильно очищаете свои объекты.

Учитывая (я предполагаю), что вы выделяете новые ListElements в куче в классе LinkedList, вы должны убедиться, что в деструкторе LinkedList каждый ListElement удален в деструкторе, пройдя по списку и вызвав delete для каждого ListElement ( конечно же, после того, как вы получили из него адрес следующего элемента списка). Примерно так:

ListElement* current = list.start;    
while( current ){
    ListElement* next = current->next;
    delete current;
    current = next;
}

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

Как я уже говорил в комментариях, вам не следует использовать стек для обращения к связанному списку. Вы должны просто поменять местами указатели.
Быстрый пример того, что вам нужно.

ListElement* previous = 0;
ListElement* current = list.start;

while( current->next ){
    //copy the address of current item on the list
    ListElement* next = current->next;

    //point the current list item to the previous list item
    current->next = previous;

    //set the current list item to the next list item
    current = next;

    //and the previous list item to the current one
    previous = current;
}
//set the start of the list to what was the end
list.start = current;
...