Очистить функцию в классе узла связанного списка C++

У меня возникли проблемы с тем, чтобы убедиться, что я создал четкую функцию для класса узла связанного списка. Я использую delete this, который, как я знаю, может вызвать проблемы с памятью, но это единственный способ, который я могу придумать, чтобы убедиться, что все объекты в связанном списке удалены. Последние строки main() по-прежнему будут выводить значение головного узла, которое должно было быть удалено. Является ли это ошибкой метода или это связано с тем, что указатель все еще связан с объектом?

Очистить фрагмент метода

class Node {
private:
  Node *next = NULL;
  double value;
public:
  void clear();
};

void Node::clear() {
  cout << "Clear: " << this << ":" << value << endl;
  if(next != NULL){
    next -> clear();
  }
  delete this;
}

Полный файл


using namespace std;

class Node {
private:
  Node *next = NULL;
  double value;

public:
  Node(double);
  Node getNext(){return *next;} //inline
  void setNext(Node *newNext); //set *next
  double getValue(){return value;} //inline
  void setValue(double newValue) {value = newValue;} //inline
  void incValue(); //Increment value by the value of next node's value. If next is NULL do nothing.
  int sizeOf(); //return size of linked list
  double largest(); //return largest value in linked list
  double smallest(); //return smallest value in linked list
  double getSum(); //Get summation of all
  double average(); //return average of all values in the linked list
  void print(); //print all values in linked list
  void print_reverse(); //print all values in reverse order
  void clear(); //remove all nodes from linked list
};

Node::Node(double newValue) {
  value = newValue;
}
void Node::setNext(Node *newNext) {
  next = newNext;
}

void Node::incValue() {
  if(next != NULL) {
    double nextVal = next -> getValue();
    value += nextVal;
  }
}
int Node::sizeOf() {
  int count = 0;
  if(next != NULL)
    count = next -> sizeOf();

  count += 1;

  return count;
}
double Node::largest() {
  double large = value;
  if(next != NULL)
    large = next -> largest();

  if(value > large)
    large = value;

  return large;
}
double Node::smallest() {
  double small = value;
  if(next != NULL)
    small = next -> smallest();

  if(value < small)
    small = value;


  return small;

}
double Node::average() {
  double sum = getSum();
  int size = sizeOf();
  return sum/size;
}
double Node::getSum() {
  double sum = 0;
  int count = 0;
  if(next != NULL)
    sum += next -> getSum();
  sum += value;
  return sum;
}
void Node::print() {
  cout << value << endl;
  if(next != NULL)
    next -> print();
}
void Node::print_reverse() {
  if(next != NULL)
    next -> print_reverse();
  cout << value << endl;
}
void Node::clear() {
  cout << "Clear: " << this << ":" << value << endl;
  if(next != NULL){
    next -> clear();
  }
  delete this;
}




int main() {
  //set up linked list
  Node *head, *temp;
  temp = new Node(1);
  head = temp;
  temp = new Node(2);
  temp -> setNext(head);
  head = temp;
  temp = new Node(3);
  temp -> setNext(head);
  head = temp;
  temp = new Node(4);
  temp -> setNext(head);
  head = temp;
  temp = new Node(5);
  temp -> setNext(head);
  head = temp;
  temp = new Node(6);
  temp -> setNext(head);
  head = temp;
  temp = new Node(7);
  temp -> setNext(head);
  head = temp;
  temp = new Node(8);
  temp -> setNext(head);
  head = temp;
  //print
  cout << "Print\n";
  head -> print();
  //average
  cout << "Average\n";
  double av = head -> average();
  cout << av << endl;
  //print reverse
  cout << "Print reversed\n";
  head -> print_reverse();
  //smallest
  cout << "Smallest\n";
  double small = head -> smallest();
  cout << small << endl;
  //largest
  cout << "Largest\n";
  double  large = head -> largest();
  cout << large << endl;
  //size
  cout << "Size\n";
  int size = head -> sizeOf();
  cout << size << endl;
  //clear
  cout << "Clear\n";
  head -> clear();
  //clear print
  cout << "Clear print\n";
  head -> print();
  cout << "Clear size\n";
  cout << head -> sizeOf() << endl;

  //end of program
  cout << "End\n";
}


person Ethan Olsen    schedule 22.04.2020    source источник
comment
Фундаментальная проблема с вашим кодом заключается в том, что узел и связанный список — это две разные вещи и должны быть двумя разными классами. Например, безусловно, имеет смысл очистить связанный список, а это будет означать удаление всех узлов, которые в нем есть. Но вы написали код для очистки узла, что не имеет никакого смысла, и я думаю, это то, что вас смущает.   -  person john    schedule 22.04.2020


Ответы (2)


Вы должны редко (если вообще когда-либо) использовать delete this;. Вы также не очищаете указатель next, поэтому он становится оборванным указателем. Эта память, вероятно, все еще содержит большую часть данных, которые были там, поэтому, когда вы проходите по списку после его «очистки», вы видите старые данные, но обратите внимание, что это только один из может случиться многое, потому что доступ к объекту, который был уничтожен, является поведением undefined.

Вместо этого рассмотрите возможность сделать это:

void Node::clear() {
  cout << "Clear: " << this << ":" << value << endl;
  if(next != NULL){
    next -> clear();
    delete next;
    next = NULL;
  }
}

Еще лучше, сделайте это в деструкторе Node, а затем вы можете просто удалить целевой узел:

void Node::~Node() {
  clear();
}

void Node::clear() {
  cout << "Clear: " << this << ":" << value << endl;
  if(next != NULL){
    delete next;
    next = NULL;
  }
}

Еще лучше, сделайте next std::unique_ptr, а затем вы можете просто сбросить его на clear(), уничтожение будет автоматическим, а копирование узла строго запрещено:

class Node {
private:
  std::unique_ptr<Node> next;
  double value;
public:
  void clear();
};

void Node::clear() {
  cout << "Clear: " << this << ":" << value << endl;
  next.reset(null);
}

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

person cdhowie    schedule 22.04.2020

Все после вашего clear() поведение undefined, так как ваша переменная head была удалена в функции clear. Вы можете просто рассмотреть свой отпечаток после этого мусора.

Что касается правильного способа освобождения всего, вы должны поместить свою функцию очистки за пределы вашей структуры Node:

void clear(Node* head)
{
  Node* next = head->next;
  delete head;
  if (next != nullptr)
    clear(next);
}

Я думаю, что вызов удаления в деструкторе — это UB, так как удаление вызывает деструктор вместо вас. Как упоминалось в комментариях, delete отсутствует в деструкторе, забудьте, что я сказал!

person Thomas Caissard    schedule 22.04.2020
comment
Я думаю, что вызов удаления в деструкторе является UB, поскольку удаление вызывает деструктор вместо вас. Это просто привело бы к бесконечной рекурсии, но обратите внимание, что этого нет в деструкторе. - person cdhowie; 22.04.2020