Очистить функцию в связанном списке узлов класса C ++ - PullRequest
0 голосов
/ 22 апреля 2020

У меня проблемы с проверкой того, что я создал функцию очистки для класса узла связанного списка. Я использую 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";
}

Ответы [ 2 ]

2 голосов
/ 22 апреля 2020

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

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

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 a std::unique_ptr, а затем вы можете просто сбросить его на clear(), уничтожение происходит автоматически c и копирование Узла должным образом запрещено:

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

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

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

1 голос
/ 22 апреля 2020

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

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

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

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

...