如何使用链表修复内存泄漏?
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
-破坏 Node
s 替代 Abel 的答案:
LinkedList::~LinkedList()
{
while (head)
{
Node * temp = head;
head = head->next;
delete temp;
}
}
LinkedList
循环移除并删除第一个 Node
,直到没有 Node
剩余。
为什么我更喜欢这种方法?两个原因:
Ownership。谁负责管理节点?通过循环,管理 Node
完全掌握在 LinkedList
手中。如果 Node
s 可以互相摧毁,则管理将在 LinkedList
和 Node
之间分配,并且双方所有者需要就托管资源的状态保持一致。维护这个协议很棘手,棘手意味着你可能会出错的代码更多。例如,如果 LinkedList
在从列表中删除单个 Node
时不小心,那么 Node
将递归地破坏列表的其余部分。糟糕。
第二个原因是递归。如果列表太长,程序将耗尽其自动存储空间(通常会导致堆栈溢出)并变得不稳定。您已经限制了您可以处理不必要的列表的大小,并且您知道您已经超出限制的唯一方法是当程序失败时。
我无法重现 Asker 遇到的访问冲突。我可能不小心修复了它。
您好,我有以下代码,并且不断出现内存泄漏,请有人帮我解决这个问题,我已经处理了几个小时,但似乎无法找到内存泄漏的原因,我是新手节点,我认为问题出在析构函数上,但似乎无法准确指出问题所在,请帮忙!
#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
-破坏 Node
s 替代 Abel 的答案:
LinkedList::~LinkedList()
{
while (head)
{
Node * temp = head;
head = head->next;
delete temp;
}
}
LinkedList
循环移除并删除第一个 Node
,直到没有 Node
剩余。
为什么我更喜欢这种方法?两个原因:
Ownership。谁负责管理节点?通过循环,管理 Node
完全掌握在 LinkedList
手中。如果 Node
s 可以互相摧毁,则管理将在 LinkedList
和 Node
之间分配,并且双方所有者需要就托管资源的状态保持一致。维护这个协议很棘手,棘手意味着你可能会出错的代码更多。例如,如果 LinkedList
在从列表中删除单个 Node
时不小心,那么 Node
将递归地破坏列表的其余部分。糟糕。
第二个原因是递归。如果列表太长,程序将耗尽其自动存储空间(通常会导致堆栈溢出)并变得不稳定。您已经限制了您可以处理不必要的列表的大小,并且您知道您已经超出限制的唯一方法是当程序失败时。
我无法重现 Asker 遇到的访问冲突。我可能不小心修复了它。