0

I was looking at my textbook on how to use some basic Linked List operations in C++. I tried to test out one of the examples of using the "appendNode" member function for the class NumberList.

Here's the header file:

 #ifndef NUMBERLIST_H
#define NUMBERLIST_H

using namespace std;

class NumberList
{
    private:
        struct ListNode
        {
            double value; //The value in this node 
            struct ListNode *next; //Points to next node
        };
        
        ListNode *head; //List head pointer
        
    public:
        NumberList()
        { head = nullptr; } //Constructor
        
        ~NumberList();  //Destructor 
        
        //List operations 
        void appendNode(double);
        void insertNode(double);
        void deleteNode(double);
        void displayList() const;
};

#endif

Here's the implementation file:

    #include <iostream>
#include "NumberList.h"
using namespace std;

void NumberList::appendNode(double num)
{
    ListNode *newNode;                            //Points to new node, used to allocate and point to the new node.
    ListNode *nodePtr;                            //To move through the list, looking for the last node.
    
    //Allocate a new node and store num there.
    newNode = new ListNode;
    newNode->value = num;
    newNode->next = nullptr;                    //This is the last node in the list since its pointing to nullptr
    
    //If there are no nodes in the list, make newNode the first node
    if (!head)                                  //Tests the head pointer to determine if there are any nodes already in the list.
        head = newNode;                         //If head points to nullptr, we make the new node the first.
        
    else //Otherwise, insert newNode at end of list.
    {
        
        //Intialize nodePtr to head of list.
        nodePtr = head;                         //Uses nodePtr to travel down the list. 
        
        //Find the last node in the list.
        while (nodePtr->next)                   //Used to transverse the list searching for the last node
            nodePtr = nodePtr->next;
        
        
        //Insert newNode as the last node.
        nodePtr->next = newNode;            //When nodePtr points to the last node, we make its next member point to newNode,
                                            //This inserts newNode at the end of the list. RECALL newNode->next already points to nullptr.
    }
}

void NumberList::insertNode(double num)
{
    ListNode *newNode;                  //A new node
    ListNode *nodePtr;                  //To transverse the list
    ListNode *previousNode = nullptr;   //The previous node
    
    //Allocate a new node and store num there
    newNode = new ListNode;
    newNode->value = num;
    
    //If there are no nodes in the list make newNode the first node.
    if (!head)
    {
        head = newNode;
        newNode->next = nullptr;
    }
    else                                //Otherwise insert newNode 
    {
        //Postion nodePtr at the head of list 
        nodePtr = head; 
        
        //Intialize previousNode to nullptr.
        previousNode = nullptr;
        
        //Skip all nodes whose value is less than num.
        while (nodePtr != nullptr && nodePtr->value < num)
        {
            previousNode = nodePtr;
            nodePtr = nodePtr->next;
        }
        
        //If the new node is to be the 1st on the list, insert it before all other nodes.
        if (previousNode == nullptr)
        {
            head = newNode;
            newNode->next = nodePtr;
        }
        else                            //Otherwise insert after the previous node.
        {
            previousNode->next = newNode;
            newNode->next = nodePtr;
        }
    }
}

void NumberList::deleteNode(double num)
{
    ListNode *nodePtr;          //To transverse the list 
    ListNode *previousNode;     //To point to the previous node
    
    //If the list is empty, do nothing 
    if (!head)
        return;
    
    //Determine if the first node is the one.
    if (head->value == num)
    {
        nodePtr = head->next;
        delete head;
        head = nodePtr;
    }
    else
    {
        //Intialize nodePtr to head of list 
        nodePtr = head;
        
        //Skip all nodes whose value member is not equal to num 
        while (nodePtr != nullptr && nodePtr->value !=num)
        {
            previousNode = nodePtr;
            nodePtr = nodePtr->next;
        }
        
        //If nodePtr is not at the end of the list, link the previous node to the node after nodePtr, then delete nodePtr.
        if (nodePtr)
        {
            previousNode->next = nodePtr->next;
            delete nodePtr;
        }
    }
}

void NumberList::displayList() const
{
    ListNode *nodePtr;  //To move through list 
    
    //Postion nodePtr at the head of list 
    nodePtr = head;
    
    //While nodePtr points to a node, transverse the list 
    while (nodePtr)
    {
        //Display the value in this node 
        cout << nodePtr->value << endl;
        
        //Move to the next node
        nodePtr = nodePtr->next;
    }
}

And here's the driver file:

 #include <iostream>
#include "NumberList.h"
using namespace std;

int main()
{
    NumberList list;
    
    list.appendNode(2.5);
    list.appendNode(7.9);
    list.appendNode(12.6);
    return 0;
}

After compiling the code I'm getting the error that says:

main.cpp:(.text+0x76): undefined reference to `NumberList::~NumberList()'
main.cpp:(.text+0x89): undefined reference to `NumberList::~NumberList()'
collect2: error: ld returned 1 exit status

In the main function.

Please let me know why this error is happening! (NOTE: the main function in this example is not supposed to display anything).

Thanks.

Cyrus Lee
  • 27
  • 4
  • 2
    I see that you declared `~NumberList()` in the header but I cannot find the definition (implementation) of it. The linker cannot as well. Can you? – Scheff's Cat Feb 08 '21 at 06:29
  • 1
    If you believe you never use it you are wrong. `NumberList list;` default-constructs an instance of `NumberList`. When `main()` is left it has to be destructed again. The compiler adds a call to that destructor internally (where the block scope of `list` is closed). – Scheff's Cat Feb 08 '21 at 06:33
  • If you hadn't declared the user-defined destructor, the linker error would not have occurred, since the compiler would have generated its default version of one. But that's a moot point, because your linked-list class violates the [rule of 3](https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three) anyway, so a destructor, user-defined copy constructor and assignment operator would have been needed to be coded anyway. – PaulMcKenzie Feb 08 '21 at 06:46
  • Alright thanks guys, yeah I noticed that I didn't include the destructor in the implmentation file. On a side note, what should the destructor function do in its definition? – Cyrus Lee Feb 08 '21 at 06:50
  • 1
    The destructor needs to properly deallocate the memory that you used to build the linked list. Otherwise you would have memory leaks. – PaulMcKenzie Feb 08 '21 at 06:52

0 Answers0