0

I have created this Dictionary class and a Linkedlist template which takes this class as the type. In the main() function I am trying to make an object of Dictionary class and passing the Dictionary as the type for Linkedlist template. Later when I pass the created Dictionary class object to LinkedList's insertHead() or initHead() function and try to print the data through accessing the head's data and calling Dictionary member function print(), It does not prints the data (32, A). insertHead() prints a "0-" and initHead() gives segmentation fault. Is there a way I can fix the issue?

class Dictionary {
public:
    int index;
    string data;
public:
    Dictionary(int index = 0, string data = ""){
        this->index = index;
        this->data = data;
    }

    Dictionary(string data){
        this->data = data;
    }

    void setIndex(int index){
        this->index = index;
    }

    void setData(string data){
        this->data = data;
    }

    Dictionary operator=(Dictionary const & obj){
        Dictionary dict;
        dict.index = obj.index;
        dict.data = obj.data;
        return dict;
    }

    void print(){
        cout << index << "-" << data << endl;
    }

    friend bool operator== (const Dictionary &d1, const Dictionary &d2);
    friend bool operator!= (const Dictionary &d1, const Dictionary &d2);
};

bool operator== (const Dictionary &d1, const Dictionary &d2){
    return (d1.data == d2.data);
}

bool operator!= (const Dictionary &d1, const Dictionary &d2){
    return !(d1 == d2);
}


int main(){
    Dictionary d(32, "A");
    LinkedList<Dictionary> l;
    l.insertHead(d);
    l.head->data.print();
}

Here is the code for LinkedList template class:

#include <iostream>
using namespace std;

template <typename T>
class Node {
public:
    T data;
    Node *next;
    Node *prev;

    Node(){};
};

template <typename T>
class LinkedList {
public:
    Node<T> *head;
    Node<T> *tail;

public:
    LinkedList(){
        head = NULL;
        tail = NULL;
    }

    void initHead(T item){
        head->next = NULL;
        head->prev = NULL;
        head->data = item;
    }

    void insertHead(T item){
        Node<T> *tmp = new Node<T>();
        if (head == nullptr){
            head = tmp;
            head->prev = nullptr;
            head->data = item;
            head->next = nullptr;
            tail = tmp;
        } else {
            tmp->next = head;
            tmp->data = item;
            tmp->prev = nullptr;
            head->prev = tmp;
            head = tmp;
        }
    }

    void insertLast(T item){
        Node<T> *tmp = new Node<T>();
        tmp->data = item;
        if (head == nullptr){
            head = tmp;
            head->prev = nullptr;
            head->next = nullptr;
            tail = tmp;
        } else {
            tmp->prev = tail;
            tail->next = tmp;
            tmp->next = nullptr;
            tail = tmp;
        }
    }

    void insertNext(T item){
        Node<T> *tmp = new Node<T>();
        tmp->next = nullptr;
        tmp->data = item;
        tmp->prev = nullptr;

        Node<T> *iter = head;
        while (iter != nullptr){
            if (iter->next == nullptr){
                iter->next = tmp;
                tmp->prev = iter;
                return;
            }
            iter = iter->next;
        }
    }

    // Returns 0 if Not found. Always add a check
    // for 0 before accessing the tmp->data

    Node<T>* find(T item){
        Node<T> *tmp = head;
        while(tmp && tmp->data != item){
            tmp = tmp->next;
        }
        return tmp;
    }

    bool deleteNode(Node<T>* node){
        if (node == nullptr){
            return false;
        } else if (node == head){
            head = node->next;
            delete node;
            return true;
        } else {
            Node<T> *tmp = head;
            while (tmp){
                if (tmp->next == node){
                    tmp->next = node->next;
                    delete node;
                    return true;
                }
                tmp = tmp->next;
            }
        }
        return false;
    }

    void print(){
        Node<T> *tmp;
        tmp = head;
        while (tmp != nullptr){
            cout << tmp->data << "->";
            tmp = tmp->next;
        }
        cout << endl;
    }
};
MIB
  • 57
  • 6

1 Answers1

2

In the function insertHead I changed the head->data = item to next lines

head->data.index = item.index; head->data.data = item.data;

then it printed 32-A. So you have a problem with = operator overloading. Then I changed your overloading as follows:

void operator=(const Dictionary & obj){ index = obj.index; data = obj.data; }

The = operation on your Dictionary works fine now.

If you want to use original signature as you state in comments you should update previous overloading function as:

 Dictionary& operator=(Dictionary const & obj){
    this->index = obj.index;
    this->data = obj.data;
    return *this;
}

I want to improve the answer with a self assignment check. While overloading = operator, internals goes like this:

  1. Deallocate the memory hold by this
  2. Allocate the memory for given parameter object
  3. Copy values and return

Therefore, if you try something like:

Dictionary dummyDict;
dummyDict=dummyDict;

your program will blow. So the final answer will be:

Dictionary& operator=(Dictionary const & obj){
    if(this == &obj){
        return *this;
    }
    this->index = obj.index;
    this->data = obj.data;
    return *this;
}
artunc
  • 121
  • 1
  • 6
  • This is right, the operator= overload never modifies `this`, and returns a new Dictionary object by value. Effectively operator= does nothing, and leaves the object uninitialized. – Omada Dec 10 '20 at 08:04
  • But we are not supposed to modify insertHead() because it is a template. So I have to somehow modify operator=. Your answer return void. aren't we supposed to return a Dictionary object? – MIB Dec 10 '20 at 08:18
  • No we don't. It has already modified the *this objects attributes with assignment. – artunc Dec 10 '20 at 08:19
  • insertHead() is now working fine, but initHead() is still giving seg fault. – MIB Dec 10 '20 at 08:24
  • 1
    As far as I see in initHead you are trying to access the data attribute of NULL, you have to initialize head Node first e.g. using new. – artunc Dec 10 '20 at 08:32
  • 1
    I previously said that you are trying to access data attribute but you are not trying to reach just data attribute but also next and prev. As I mentioned previously, before doing this you have to initialize head node first because it is NULL. – artunc Dec 10 '20 at 08:50
  • 1
    I guess instead of self-assignment check one should prefer [copy-swap idiom](https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom) whenever possible. It is a canonical and clear way to implement assignment without code duplication in copy ctor and assignment operator. It also doesn't need any special self assignment checks (though for self assignment it will do more job that could have been done, but in most cases that's irrelevant). But in this particular case (`int` and `std::string` members) self-assignment won't hurt. – Evg Dec 10 '20 at 21:24