mercredi 27 janvier 2021

How to properly use template class with an abstract pointer type

I created a List with a template Node class to hold different data types such as Node<int> but also more complex types such as Node<BaseEvent*>.

I also have an event container class to hold different event objects so it has a member argument

List<BaseEvent*> events;

where BaseEvent is an abstract class with derived classes that are not abstract.

In the event container I have a method called "add" (see below) that adds a new event to that events.

BaseEvent* eventClone = event.clone();

The clone returns a pointer to a new derived object such as:

new OpenEvent(*this);

Once it calls the list's insert method, it instantiates a new Node (see below), and in the Node constructor it assigns the value like so:

value(new T(new_value)) 

So basically it allocates a pointer memory (T=BaseEvent*).

I think I might be losing the eventClone pointer and have a memory leak. The problem is that when I debugged it I saw that both: T* value; (aka BaseEvent** value) and BaseEvent* eventClone have the same address in memory.

I'm not sure if when I do delete value in the destructor of Node it will just free the pointer allocation to BaseEvent* or also the data that it holds.

Any insights are welcome!


Relevant code snippets

Node<T>

    template <class T>
    class Node
    {
    public:

        Node(const T& new_value, Node* new_next = NULL, Node* new_prev = NULL);
        ~Node();

        const T& getValue() const;
        Node<T>* getNext() const;
        Node<T>* getPrev() const;
        void setNext(Node* node);
        void setPrev(Node* node);

    private:
        T* value;
        Node* next;
        Node* prev;
    };

    template <class T>
    Node<T>::Node(const T& new_value, Node* new_next, Node* new_prev) : 
        value(new T(new_value)) 
    {
        next = new_next;
        prev = new_prev;
    }

    template <class T>
    Node<T>::~Node()
    {
        delete value;
    }
    ...

Linked list that uses Node<T>

    template <class T>
    class List
    {
    public:
        List();
        ~List();
        
        int getSize() const;
        Node<T>* getFirst() const;
        Node<T>* getNext(Node<T>& node) const;
        Node<T>* getPrev(Node<T>& node) const;
        void insertStart(const T& data);
        void insertLast(const T& data);
        void insertAfter(Node<T>& target, const T& data);
        void insertBefore(Node<T>& target, const T& data);
        void removeNode(Node<T>& node);
        bool contains(const T data);


    private:
        Node<T>* head;
        int size;
    };

    template <class T>
    List<T>::List() : head(NULL), size(0)
    {
    }

    template <class T>
    List<T>::~List()
    {
        Node<T>* temp;
        while (head)
        {
            temp = head;
            head = head->getNext();
            delete temp;
            size--;
        }
    }
    ...
    template <class T>
    void List<T>::insertStart(const T& data) {
        if (size == 0)
        {
            head = new Node<T>(data);
        }
        else
        {
            Node<T>* temp = new Node<T>(data, head);
            head->setPrev(temp);
            head = temp;
        }

        size++;
    }
    ...

The event container class:

    class EventContainer
    {
    public:
        EventContainer() :
            events(List<BaseEvent*>()) {}
        ~EventContainer() {}

        virtual void add(const BaseEvent&);
        
        class EventIterator
        {
        public:
            EventIterator() :
                current(NULL) {}
            EventIterator(Node<BaseEvent*>& node) :
                current(&node) {}
            EventIterator(Node<BaseEvent*>* node) :
                current(node) {}
            ~EventIterator() {}

            EventIterator& operator=(const EventIterator& nodeIterator) {
                current = nodeIterator.current;
                return *this;
            }
            EventIterator& operator++() {
                current = current->getNext();
                return *this;
            }
            BaseEvent& operator*() const {
                return *(current->getValue());
            }

            friend bool operator==(const EventIterator& iterator1, const EventIterator& iterator2) {
                return iterator1.current == iterator2.current;
            }

            bool operator!=(const EventIterator& iterator) const {
                return !(*this == iterator);
            }

        private:
            Node<BaseEvent*>* current;
        };

        virtual EventIterator begin() const;
        virtual EventIterator end() const;

    private:
        List<BaseEvent*> events;
    };

The implementation of add method:

    void EventContainer::add(const BaseEvent& event) {
        BaseEvent* eventClone = event.clone();
        if (events.getSize() == 0)
        {
            events.insertStart(eventClone);
            return;
        }

        Node<BaseEvent*>* current = events.getFirst();
        while (current != NULL)
        {
            if (*eventClone < *(current->getValue()))
            {
                events.insertBefore(*current, eventClone);
                return;
            }
            current = current->getNext();
        }

        events.insertLast(eventClone);
    }

    EventContainer::EventIterator EventContainer::begin() const {
        return events.getFirst();
    }
    
    EventContainer::EventIterator EventContainer::end() const {
        return NULL;
    }

Aucun commentaire:

Enregistrer un commentaire