Search code examples
c++pointerslinked-listdynamic-memory-allocation

Linked List exercise, what am I doing wrong?


Hey all. I'm doing a linked list exercise that involves dynamic memory allocation, pointers, classes, and exceptions. Would someone be willing to critique it and tell me what I did wrong and what I should have done better both with regards to style and to those subjects I listed above?

/*

Linked List exercise

*/

#include <iostream>
#include <exception>
#include <string>
using namespace std;

class node{
public:
    node * next;
    int * data;
    node(const int i){
        data = new int;
        *data = i;
    }
    node& operator=(node n){
        *data = *(n.data);
    }
    ~node(){
        delete data;
    }
};

class linkedList{

public:

    node * head;
    node * tail;
    int nodeCount;

    linkedList(){
        head = NULL;
        tail = NULL;
    }

    ~linkedList(){
        while (head){
            node* t = head->next;
            delete head;
            if (t) head = t;
        }
    }

    void add(node * n){
        if (!head) {
            head = n;
            head->next = NULL;
            tail = head;
            nodeCount = 0;
        }else {
            node * t = head;
            while (t->next) t = t->next;
            t->next = n;
            n->next = NULL;
            nodeCount++;
        }
    }

    node * operator[](const int &i){
        if ((i >= 0) && (i < nodeCount)) throw new exception("ERROR:  Invalid index on linked list.", -1);
        node *t = head;
        for (int x = i; x < nodeCount; x++) t = t->next;
        return t;
    }

    void print(){
        if (!head) return;
        node * t = head;
        string collection;
        cout << "[";
        int c = 0;
        if (!t->next) cout << *(t->data);
        else while (t->next){
            cout << *(t->data);
            c++;
            if (t->next) t = t->next;
            if (c < nodeCount) cout << ", ";
        }
        cout << "]" << endl;
    }

};

int main (const int & argc, const char * argv[]){

    try{
        linkedList * myList = new linkedList;
        for (int x = 0; x < 10; x++) myList->add(new node(x));
        myList->print();
    }catch(exception &ex){
        cout << ex.what() << endl;
        return -1;
    }   
    return 0;
}

Solution

  • There's no need for data to be a pointer.

    Use the ctor-initializer list, it's better for const-correctness and exception safety. None of your constructors need to have any code inside the body.

    Your linkedList constructor didn't initialize nodeCount.

    You aren't using your list's tail pointer for anything. It would save you scanning through the entire list in the non-empty case of add -- if you kept it up to date.

    Indexing (operator[]) is an unusual thing to support on a linked list. OTOH you haven't made a remove function.

    operator[] shouldn't take its parameter by reference. Only large structures need to be passed by const reference, small type like int should just be passed by value.

    Right now, if add fails, the pointer to new node() leaks. (But I don't actually see a way for add to fail unless the list links got corrupted.)

    You should define a private copy-constructor on node to prevent double-free of the data. Any time you define operator= and destructor you should also be defining or deleting the copy constructor (rule of three). You should also define private copy constructor and assignment operator on linkedList to prevent double-free.

    The variable string collection in your print function isn't used. The variable t in print() should be a pointer to const. print itself should be a const member function.