Search code examples
c++memory-managementdestructorsingly-linked-listrecursive-datastructures

Deleting node containing address of other node


I know the logic in the code given below is wrong but I have doubts about what happens when we delete p having the address of the next node.

What will the destructor do? will it go to all the node make them null until the Next in node p don't become null

Also tell me what destructors do to memory. I have read many articles on destructor, deallocation ,delete and free but I am still confused. Main confusion is in deallocation and destructor.

class Node {
    public:
        int data;
        Node * next;
        Node(int data){
            this -> data = data;
            this -> next = NULL;
        }
    
        ~Node() {
            if(next) {
                delete next;
            }
        }
    };
void deleteAlternateNodes(Node *head) {
    //Write your code here
    Node *p =head;
    Node *q =NULL;
   if(p->next == NULL)
   {
       return;
   }
    while(p!=NULL)
    {
        q=p;
        p=p->next;
        q->next = p->next;
        delete p;
        p = q->next;
    }
}

Solution

  • In this statement of the operator delete

    delete p;
    

    all nodes that follow the node pointed to by the pointer p (due to the data member next) will be deleted.

    So the function deleteAlternateNodes invokes undefined behavior because all nodes pointed to by the expression q->next that is assigned like

        q->next = p->next;
    

    will be deleted due to this statement

        delete p;
    

    So this statement

        p = q->next;
    

    sets the pointer p to an invalid pointer.

    Here is a demonstrative program

    #include <iostream>
    
    class Node 
    {
    public:
        int data;
        Node * next;
        
        Node(int data)
        {
            this -> data = data;
            this -> next = NULL;
        }
        
        ~Node() 
        {
            std::cout << "The destructor is called for node with data equal to "
                      << data << '\n';
    
            if(next) 
            {
                delete next;
            }
        }
    };
    
    void display( const Node *head )
    {
        for ( ; head; head = head->next )
        {
            std::cout << head->data << " -> ";
        }
        
        std::cout << "null\n";
    }
    
    int main() 
    {
        Node *head = new Node( 1 );
        Node *current = head;
        current->next = new Node( 2 );
        current = current->next;
        current->next = new Node( 3 );
        
        display( head );
        
        delete head;
        
        return 0;
    }
    

    The program output is

    1 -> 2 -> 3 -> null
    The destructor is called for node with data equal to 1
    The destructor is called for node with data equal to 2
    The destructor is called for node with data equal to 3
    

    In fact the if statement in the destructor is redundant

            if(next) 
            {
                delete next;
            }
    

    You may just write

    delete next;
    

    without the if statement because for a null pointer the destructor will not be called. For example

    ~Node() 
    {
        std::cout << "The destructor is called for node with data equal to "
                  << data << '\n';
    
        delete next;
    }
    

    or

    ~Node() 
    {
        delete next;
    }