Search code examples
listlinked-listoperator-overloadingdynamic-data

Uniting a dynamic list in C++ with overloaded operators


So, I've been on the process of making a linked list class, and right now I'm trying to make it so that two lists can be united through simple a + operator. Here is the current code, whole:

#include <iostream>
using namespace std;

// ---/ List Class /--- //

template <class Type>
struct Node {
    Type core;
    Node<Type> *next;
};

template <class Type>
class List {
    public:
        Node<Type> *start, *end;
        unsigned int siz;

        static const int END;

    public:
        // Genesis
        List() {
            start = NULL;
            end = NULL;

            siz = 0;
        };

        // ---
        void push (const Type&, const int&);

        // DEBUG
        void show (void);

        // +-*/
        List operator+ (const List&);
        List& operator= (const List&);
        List& operator+= (const List&);

        // Abbadon
        ~List() {
            delete start;
            delete end;
        };
};

template <class Type>
const int List<Type>::END = -1;

// ---

template <class Type>
void List<Type>::push (const Type& elem, const int& pos = END) {
    Node<Type> *aux;

    aux = new Node<Type>;
    aux->core = elem;

    if (siz == 0) {
        aux->next = NULL;

        start = aux;
        end = aux;
    }
    else {
        if (pos == END) {
            aux->next = NULL;

            end->next = aux;
            end = end->next;
        }
        else if (pos == 0) {
            aux->next = start;

            start = aux;
        }
        else {
            Node<Type> *pesq = start;
            for (int i = 1; (i < pos) && (pesq->next != NULL); i++) {
                pesq = pesq->next;
            }

            aux->next = pesq->next;
            pesq->next = aux;
        }
    }

    siz++;
}

// DEBUG

template <class Type>
void List<Type>::show (void) {
    Node<Type> *pesq = start;
    while (pesq != NULL) {
        cout << pesq->core << endl;
        pesq = pesq->next;
    }

    cin.get();
}

// +-*/

template <class Type>
List<Type> List<Type>::operator+ (const List<Type>& nimda) {
    List<Type> aux = *this;

    aux.end->next = nimda.start;
    aux.end = nimda.end;

    aux.siz += nimda.siz;

    return aux;
}

template <class Type>
List<Type>& List<Type>::operator= (const List<Type>& nimda) {
    if (&nimda != this) {
        start = nimda.start;
        end = nimda.start;
        siz = nimda.siz;
    }
} 

template <class Type>
List<Type>& List<Type>::operator+= (const List<Type>& nimda) {
    *this = *this + nimda;  
    return *this;
}

// ---/ MAIN() /--- //

int main() {
    List<int> adabo;
    List<int> inakos;

    adabo.push(1);
    adabo.push(2);

    inakos.push(3);
    inakos.push(4);

    adabo = adabo + inakos;

    adabo.show();
}

Here are the overloaded operators:

template <class Type>
List<Type> List<Type>::operator+ (const List<Type>& nimda) {
    List<Type> aux = *this;

    aux.end->next = nimda.start;
    aux.end = nimda.end;

    aux.siz += nimda.siz;

    return aux;
}

template <class Type>
List<Type>& List<Type>::operator= (const List<Type>& nimda) {
    if (&nimda != this) {
        start = nimda.start;
        end = nimda.start;
        siz = nimda.siz;
    }
} 

template <class Type>
List<Type>& List<Type>::operator+= (const List<Type>& nimda) {
    *this = *this + nimda;  
    return *this;
}

And here is the main(), for testing:

// ---/ MAIN() /--- //

int main() {
    List<int> adabo;
    List<int> inakos;
    List<int> foo;

    adabo.push(1);
    adabo.push(2);

    inakos.push(3);
    inakos.push(4);

    foo = adabo + inakos;

    foo.show();
}

Its output would supposedly be the values 1, 2, 3, and 4, and it indeed happens when I put the show function in the operator of + before aux returns:

template <class Type>
List<Type> List<Type>::operator+ (const List<Type>& nimda) {
    List<Type> aux = *this;

    aux.end->next = nimda.start;
    aux.end = nimda.end;

    aux.siz += nimda.siz;

    aux.show() // Putting it here shows everything as expected

    return aux;
}

It seems, however, that 'aux' is lost somewhere between its return of the function and the actual value received by 'foo' in main(), causing foo.show() to display random data endlessly.

What am I doing wrong?


Solution

  • Nevermind, found the problem!

    What was happening was that operator= was making a 'duplicate', if one so can say, of the List to be passed over. The 'duplicate' List, when modified, would modify the original List as well, so in here...

    template <class Type>
    List<Type> List<Type>::operator+ (const List<Type>& nimda) {
        List<Type> aux = *this; // ...aux, which would become a duplicate of the class...
    
        aux.end->next = nimda.start;
        aux.end = nimda.end;
    
        aux.siz += nimda.siz;
    
        return aux;
    } // ...when destructed here, would destruct *this just as well, making all data be lost.
    

    To solve this problem, instead of blandly passing over the pointers in the overloaded =...

    template <class Type>
    List<Type>& List<Type>::operator= (const List<Type>& nimda) {
        if (&nimda != this) {
            start = nimda.start;
            end = nimda.start;
            siz = nimda.siz;
        }
    } 
    

    ...now it is made so that each element of the List is copied one by one:

    template <class Type>
    List<Type>& List<Type>::operator= (const List<Type>& nimda) {
        if (&nimda != this) {
            kill();
    
            Node<Type> *aux = nimda.start;
            while (aux != NULL) {
                push(aux->core);
                aux = aux->next;
            }
        }
    }
    

    This way, the receiving List gets a copy of all the elements of the original List without becoming itself.