如何使用链表修复内存泄漏?

How to fix memory leak with linked list?

您好,我有以下代码,并且不断出现内存泄漏,请有人帮我解决这个问题,我已经处理了几个小时,但似乎无法找到内存泄漏的原因,我是新手节点,我认为问题出在析构函数上,但似乎无法准确指出问题所在,请帮忙!

#include <iostream>

using namespace std;

class Node {
 public:
  int data;
  Node* next;
};

class LinkedList {
 public:
  LinkedList() {  // constructor
    head = NULL;
  }
  ~LinkedList();  // destructor
  void insert(int val);
  void display();

 private:
  Node* head;
};


LinkedList::~LinkedList() { delete head; }
// function to add node to a list
void LinkedList::insert(int val) {
  Node* newnode = new Node();
  newnode->data = val;
  newnode->next = NULL;
  if (head == NULL) {
    head = newnode;
  } else {
    Node* temp = head;  // head is not NULL
    while (temp->next != NULL) {
      temp = temp->next;  // go to end of list
    }
    temp->next = newnode;  // linking to newnode
  }
}

void LinkedList::display() {
  if (head == NULL) {
    cout << "List is empty!" << endl;
  } else {
    Node* temp = head;
    while (temp != NULL) {
      cout << temp->data << " ";
      temp = temp->next;
    }
    cout << endl;
  }
}

int main() {
  LinkedList* list = new LinkedList();
  list->insert(999);
  list->insert(200);
  list->insert(300);
  list->insert(700);
  list->insert(500);
  cout << "Linked List data" << endl;
  list->display();
  delete list;
  return 0;
}

我不认为你想破坏一个节点来删除整个列表。你可以,但我认为每个节点都应该独立于其他节点——链表 class 是列表级事情应该发生的地方。

此外,您不希望析构函数包含清除列表的代码,因为您可能希望在任意点清除列表 - 因此链表应该有一个从链接调用的清除函数列出析构函数,也可以从其他地方调用。

所以析构函数会调用这个函数来清除列表:

void LinkedList::clear() {
    Node* next;
    Node* temp = head;
    while (temp != NULL) {
        next = temp->next;
        delete temp;
        temp = next;
    }
    head = NULL;
}

整个代码为:

#include <iostream>
using namespace std;

class Node {
public:
    int data;
    Node* next;
    Node() : data(0), next(NULL) {
        cout << "Constructed default node\n";
    }
    Node(int data) : data(data), next(NULL) {
        cout << "Constructed node: " << data << "\n";
    }
    ~Node() {
        cout << "Destructed node: " << data << "\n";
    }
};

class LinkedList{
public:
    LinkedList() { // constructor
        head = NULL;
    }
    ~LinkedList() {
        clear();
    }
    void insert(int val);
    void display();
    void clear();
private:
    Node* head;
};

// function to add node to a list
void LinkedList::insert(int val) {
    Node* newnode = new Node(val);
    if (head == NULL) {
        head = newnode;
    }
    else {
        Node* temp = head; // head is not NULL
        while (temp->next != NULL) { 
            temp = temp->next; // go to end of list
        }
        temp->next = newnode; // linking to newnode
    }
}

// function to delete the entire list
void LinkedList::clear() {
    Node* next;
    Node* temp = head;
    while (temp != NULL) {
        next = temp->next;
        delete temp;
        temp = next;
    }
    head = NULL;
}

// function to display the entire list
void LinkedList::display() {
    if (head == NULL) {
        cout << "List is empty!" << endl;
    }
    else {
        Node* temp = head;
        while (temp != NULL) {
            cout << temp->data << " ";
            temp = temp->next;
        }
        cout << endl;
    }
}

int main() {
    LinkedList list;
    cout << "Creating List\n";
    list.insert(999);
    list.insert(200);
    list.insert(300);
    list.insert(700); 
    list.insert(500);
    cout << "Linked List data:\n";
    list.display();
    cout << "Clearing list\n";
    list.clear();
    cout << "Creating List\n";
    list.insert(400);
    list.insert(600);
    cout << "Linked List data:\n";
    list.display();
    cout << "NOT clearing list (should happen automatically\n";
    return 0;
}

您可以在这里尝试:https://onlinegdb.com/HJlOT1ngqP

输出:

Creating List
Constructed node: 999
Constructed node: 200
Constructed node: 300
Constructed node: 700
Constructed node: 500
Linked List data:
999 200 300 700 500 
Clearing list
Destructed node: 999
Destructed node: 200
Destructed node: 300
Destructed node: 700
Destructed node: 500
Creating List
Constructed node: 400
Constructed node: 600
Linked List data:
400 600 
NOT clearing list (should happen automatically
Destructed node: 400
Destructed node: 600

Node-破坏 Nodes 替代 Abel 的答案:

LinkedList::~LinkedList()
{
    while (head)
    {
        Node * temp = head;
        head = head->next;
        delete temp;
    }
}

LinkedList 循环移除并删除第一个 Node,直到没有 Node 剩余。

为什么我更喜欢这种方法?两个原因:

Ownership。谁负责管理节点?通过循环,管理 Node 完全掌握在 LinkedList 手中。如果 Nodes 可以互相摧毁,则管理将在 LinkedListNode 之间分配,并且双方所有者需要就托管资源的状态保持一致。维护这个协议很棘手,棘手意味着你可能会出错的代码更多。例如,如果 LinkedList 在从列表中删除单个 Node 时不小心,那么 Node 将递归地破坏列表的其余部分。糟糕。

第二个原因是递归。如果列表太长,程序将耗尽其自动存储空间(通常会导致堆栈溢出)并变得不稳定。您已经限制了您可以处理不必要的列表的大小,并且您知道您已经超出限制的唯一方法是当程序失败时。

我无法重现 Asker 遇到的访问冲突。我可能不小心修复了它。