![](/img/trans.png)
[英]Can one deallocate memory in a destructor if they allocated memory within a private function in C++?
[英]How do I properly deallocate memory for a merged LL in the destructor function in c++?
我用一些操作创建了一个链接列表 class 。
我正在尝试将两个链表合并在一起,如main
function 所示。 我能够成功地执行该操作并将其显示在屏幕上。
不过,我怀疑在实现尾节点的next
指针时我可能做错了什么。 当调用析构函数时,我打开调试器以查看到底发生了什么。 它成功删除了所有节点,并显示old->next
和随后head
确实最终等于nullptr
。 我确保析构函数仅在nullptr
的空操作为 false 时循环。
但是,由于某种原因,析构函数继续循环,程序给了我错误:
LinkedList(2000,0x1000d3dc0) malloc:object 0x1007239d0 的错误:未分配被释放的指针
我知道解决方案可能很明显,但我完全被大便了。 析构函数适用于非合并列表。
class Node{
public:
int data;
Node* next;
friend class LinkedList;
};
class LinkedList{
public:
Node* head;
public:
LinkedList()
{head = nullptr;}
~LinkedList()
{while (!empty()) remove();}
void addDataBack(int data);
void display();
void remove();
bool empty() const
{return head == nullptr;}
void merge(Node* list1, Node* list2);
};
void LinkedList::addDataBack(int data){
Node *p = new Node;
Node *t;
t = head;
p->data = data;
p->next = nullptr;
if (!head){
head = p;
}
else{
t = head;
while(t->next){
t = t->next;
}
t->next = p;
}
}
void LinkedList::display(){
Node *t = head;
while (t){
cout << t->data << endl;
t = t->next;
}
}
void LinkedList::remove(){
Node *old = head;
head = old->next;
delete old;
}
void LinkedList::insertNode(int index, int data){
Node *node = new Node;
int i = 0;
Node *t = head;
Node *p = nullptr;
node->data= data;
while ( t!= NULL){
if (index == i){
p->next = node;
node->next = t;
break;
}
p = t;
t = t->next;
i++;
}
}
void LinkedList:: merge(Node *list1, Node *list2){
Node* t = list1;
head = list1;
while (t->next) {
t = t->next;
}
t->next = list2;
}
int main(int argc, const char * argv[]) {
LinkedList list;
LinkedList list2;
list.addDataBack(8);
list.addDataBack(3);
list.addDataBack(7);
list.addDataBack(12);
list.addDataBack(9);
list.insertNode(2, 25);
list2.addDataBack(4);
list2.addDataBack(10);
LinkedList list3;
list3.merge (list.head, list2.head);
list.display();
return 0;
}
代码无法编译,因为您在 class 定义中缺少插入 function 原型。
见insertNode function; 在p->next = node
行中,如果 index 为 0,则此行将间接指向 null 指针并引发异常。
这是它的外观。
void LinkedList::insertNode(int index, int data)
{
Node* newNode = new Node;
newNode->data = data;
//Wrap this up quick if the list is already empty.
if (head == nullptr)
{
head = newNode;
return;
}
int i = 0;
Node* current = head;
Node* prev = nullptr;
while (current != nullptr)
{
if (index == i)
{
newNode->next = current;
if (prev)
prev->next = newNode;
return;
}
prev = current;
current = current->next;
i++;
}
//if (index >= i)
//Either delete the new node, or throw an out of bounds exception.
//Otherwise this will result in a memory leak. Personally, I think
//throwing the exception is correct.
delete newNode;
}
您的合并 function 有点令人困惑,因为您实际上是从两个列表创建一个新列表,但不是通过构造函数,而是简单地合并它们。 这将意味着 list1 在功能上等同于 list3,但地址都是混合的。 这意味着当我们退出主 function scope 时,您将从 list1 中删除 memory,然后当它再次崩溃时,list3 之前也会这样做(尽管它会删除它们)
为什么不简单地让它取一个列表,然后将两者合并呢?
#include <iostream>
#include <string>
using namespace std;
class Node{
public:
int data;
Node* next;
friend class LinkedList;
};
class LinkedList{
public:
Node* head;
public:
LinkedList()
{head = nullptr;}
~LinkedList();
void addDataBack(int data);
void display();
void remove();
void insertNode(int index, int data);
bool empty() const
{return head == nullptr;}
void merge(LinkedList& otherList);
};
LinkedList::~LinkedList()
{
while (!empty())
remove();
}
void LinkedList::addDataBack(int data){
Node *p = new Node;
Node *t;
t = head;
p->data = data;
p->next = nullptr;
if (!head){
head = p;
}
else{
t = head;
while(t->next){
t = t->next;
}
t->next = p;
}
}
void LinkedList::display(){
Node *t = head;
while (t){
cout << t->data << endl;
t = t->next;
}
}
void LinkedList::remove(){
Node *old = head;
head = old->next;
delete old;
old = nullptr;
}
void LinkedList::insertNode(int index, int data)
{
Node* newNode = new Node;
newNode->data = data;
//Wrap this up quick if the list is already empty.
if (head == nullptr)
{
head = newNode;
return;
}
int i = 0;
Node* current = head;
Node* prev = nullptr;
while (current != nullptr)
{
if (index == i)
{
newNode->next = current;
if (prev)
prev->next = newNode;
return;
}
prev = current;
current = current->next;
i++;
}
//if (index >= i)
//Either delete the new node, or throw an out of bounds exception.
//Otherwise this will result in a memory leak. Personally, I think
//throwing the exception is correct.
delete newNode;
}
void LinkedList:: merge(LinkedList& otherList){
Node* thisTail = head;
while (thisTail->next) {
thisTail = thisTail->next;
}
thisTail->next = otherList.head;
otherList.head = nullptr;
}
int main(int argc, const char * argv[]) {
LinkedList list;
LinkedList list2;
list.addDataBack(8);
list.addDataBack(3);
list.addDataBack(7);
list.addDataBack(12);
list.addDataBack(9);
list.insertNode(2, 25);
list2.addDataBack(4);
list2.addDataBack(10);
list.merge(list2);
list.display();
list2.display();
cout << "list2 is " << (list2.empty() ? "empty." : "not empty");
return 0;
}
尽量避免使用单字母变量,除非它们用于迭代,否则(尤其是链表和指针杂耍)很难维护、调试和获得帮助。
但是,由于某种原因,析构函数继续循环并 [...]
我对此表示怀疑,但如果您没有足够仔细地观察(特别是观察this
指针的值),这似乎是正在发生的事情。 在我看来, list3
的析构函数将完成循环,此时list2
的析构函数将开始(以相反的构造顺序销毁)。 如果您错过了这种转换,那么它很可能看起来像析构函数正在继续,而实际上它被第二次调用了。
由于您从未更改list2.head
,它仍然指向已合并到list3
的节点之一。 当list2
的析构函数启动时, head
仍然指向刚刚被list3
的析构函数删除的节点之一。 尝试删除已删除的节点是错误的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.