繁体   English   中英

如何在 c++ 的析构函数 function 中为合并的 LL 正确释放 memory?

[英]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 指针并引发异常。

  • 如果您提供当前节点数之外的索引 - 1
  • 如果当前列表为空,则 insertNode function 将泄漏 memory

这是它的外观。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM