简体   繁体   中英

How do I properly deallocate memory for a merged LL in the destructor function in c++?

I've created a link list class with some operations.

I am trying to merge two linked lists together, as shown in the main function. I am able to successfully do that operation and have it display on the screen.

I suspect I may be doing something wrong, though, with implementing the tail node's next pointer. When the destructor is called, I turn on the debugger to see what is going on exactly. It deletes all of the nodes successfully and shows that old->next and subsequently head do end up equaling nullptr . I made sure for the destructor to only loop when the empty operation is false for nullptr .

But, for some reason, the destructor continues looping and the program gives me the error:

LinkedList(2000,0x1000d3dc0) malloc: error for object 0x1007239d0: pointer being freed was not allocated

I know the solution may be obvious, but I am completely pooped. The destructor works fine for non-merged lists.

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;
}
  • The code does not compile because you're missing the insert function prototype in the class definition.

  • See the insertNode function; in the line p->next = node , if index is 0, then this line is going to indirect a null pointer and throw an exception.

  • The insertNode function will leak memory if you provide an index outside the current number of nodes - 1
  • The insertNode function will leak memory if the current list is empty

Here is how it should look.

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;
}

Here is the main issue:

Your merge function is a bit confusing, because you are essentially creating a new list from two lists, but not via a constructor, but simply merging them. This will mean that list1 is functionally equivalent to list3, but the addresses are all intermingled. This means that when we exit the main function scope, you will be deleting memory from list1, and then when it destroys list2 it will ALSO delete them again, and list3 will do the same (though it will have crashed before then).

Why not simply make it take one list and then merge the two?

#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;
}

Final Note:

Try to avoid single letter variables unless they are used for iteration, otherwise (especially with linked lists and pointer juggling) it is very difficult to maintain, debug and receive help for.

But, for some reason, the destructor continues looping and [...]

I doubt that, but this is what might appear to be happening if you are not watching closely enough (in particular, watching the value of the this pointer). It looks to me as though the destructor of list3 will finish looping, at which point the destructor of list2 will start (destroying in the opposite order of construction). If you miss seeing this transition, it could very well look like the destructor is continuing when it is in fact being called a second time.

Since you never changed list2.head , it is still pointing at one of the nodes that had been merged into list3 . When list2 's destructor starts, head is still pointing at one of the nodes that had just been deleted by list3 's destructor. Trying to delete that already-deleted node is an error.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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