清除链表节点节点类C ++中的函数

时间:2020-04-22 19:03:57

标签: c++ linked-list nodes delete-operator this-pointer

我在确保已为链接列表Node类创建了一个清除函数时遇到麻烦。我使用的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 个答案:

答案 0 :(得分:2)

您应该很少(如果有的话)使用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设为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);
}

请注意,最后一个节点(头)无法删除自身。正如其他人所指出的那样,清除节点除了停止指向下一个节点之外,无法进行任何其他操作。您需要为列表创建一个单独的类,然后清除它。

答案 1 :(得分:1)

clear()之后的所有内容都是未定义的行为,因为在head函数中已删除了变量clear。您可以在垃圾回收之后考虑打印。

关于释放所有内容的正确方法,应将清除函数放在Node结构之外:

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

我认为在析构函数中调用delete是UB,因为delete会为您调用析构函数。如评论中所述,在析构函数中不存在delete,忘记了我说的话!

相关问题