Home > Net >  LEAKER: errors found! memory was not deallocated
LEAKER: errors found! memory was not deallocated

Time:10-11

I keep getting the same error:

LEAKER: errors found! Leaks found: 2 allocations (48 bytes). unknown:unknown():0 memory leak: memory was not deallocated. unknown:unknown():0 memory leak: memory was not deallocated.

I keep checking my destructor and my Clear() function, but I can't figure out what I am missing. I know I should delete something but I can't figure out what I am supposed to delete. When I try to delete head or tail, I get an error saying the pointer was never allocated. Please help!

#pragma once
#include <iostream>
#include <exception>
#include <vector>
using namespace std;

template <typename T>
class LinkedList
{
public:
    // Nested Class
    struct Node
    {
        T data;                 // the data being stored
        Node* next;             // pointer to the next node
        Node* prev;             // the pointer to the previous node
        // Ensure next and previous are nullptr by default
        Node()
        {
            next = nullptr;
            prev = nullptr;
        }
    };
    
    // Default Constructor
    LinkedList();

    // Copy Constructor
    LinkedList(const LinkedList<T>& list);

    // Insertion
    void AddHead(const T& data);
    void AddTail(const T& data);
    void AddNodesHead(const T* data, unsigned int count);
    void AddNodesTail(const T* data, unsigned int count);
    void InsertAfter(Node* node, const T& data);
    void InsertBefore(Node* node, const T& data);
    void InsertAt(const T& data, unsigned int index);

    // Removal
    bool RemoveHead();
    bool RemoveTail();
    unsigned int Remove(const T& data);
    bool RemoveAt(unsigned int index);
    void Clear();

    // Accessors
    unsigned int NodeCount() const;
    void FindAll(vector<Node*>& outData, const T& value) const;
    const Node* Find(const T& data) const;
    Node* Find(const T& data);
    const Node* GetNode(unsigned int index) const;
    Node* GetNode(unsigned int index);
    Node* Head();
    const Node* Head() const;
    Node* Tail();
    const Node* Tail() const;

    // Behaviors
    void PrintForward() const;
    void PrintReverse() const;
    void PrintForwardRecursive(const Node* mode) const;
    void PrintReverseRecursive(const Node* mode) const;

    // Operators
    const T& operator[](unsigned int index) const;
    T& operator[](unsigned int index);
    bool operator==(const LinkedList<T> rhs) const;
    LinkedList<T>& operator=(const LinkedList<T>& rhs);

    // Destructor
    ~LinkedList();

private: 
    Node* head = new Node;          // Node pointer for the head
    Node* tail = new Node;          // Node pointer for the tail
    unsigned int count;             // counting nodes in list
};

// ========================== CLASS DECLARATIONS & FUNCTION DEFINITIONS ========================== //

template <typename T>
LinkedList<T>::LinkedList()
{
    // Default Constructor
    count = 0;
    head = nullptr;
    tail = nullptr;
}

template <typename T>
LinkedList<T>::LinkedList(const LinkedList<T>& list)
{
    // Copy Constructor
    this->count = 0;
    this->head = nullptr;
    this->tail = nullptr;

    Node* copy = list.head;
    while (copy != nullptr)
    {
        AddTail(copy->data);
        copy = copy->next;
    }
}

template <typename T>
void LinkedList<T>::AddHead(const T& data)
{
    Node* temp = new Node;              // Create a new node
    temp->data = data;                  // assign data being passed in to the node
    temp->next = nullptr;               // set the "next" to null
    temp->prev = nullptr;               // set the "prev" to null

    if (head == nullptr)                // if there is no head
    {
        head = temp;                    // basically makes a list of just this node
        tail = temp;
        head->next = nullptr;
        head->prev = nullptr;
    }
    else
    {
        head->prev = temp;
        if (count == 1)
        {
            tail->prev = temp;
        }
        temp->next = head;              // if there is a head, set the current head as next
        head = temp;                    // set the temp as the head
    }
    count  ;                            // increase the number of nodes
}

template <typename T>
void LinkedList<T>::AddTail(const T& data)
{
    Node* temp = new Node;              // Create a new node
    temp->data = data;                  // assign data being passed in to the node
    temp->next = nullptr;               // set the "next" to null
    temp->prev = nullptr;               // set the "prev" to null

    if (tail == nullptr)                // if there is no tail
    {
        head = temp;                    // basically makes a list of just this node
        tail = temp;
        tail->next = nullptr;
        tail->prev = nullptr;
    }
    else
    {
        tail->next = temp;
        if (count == 1)
        {
            head->next = temp;
        }
        temp->prev = tail;              // if there is a tail, set the current tail as previous
        temp->next = nullptr;
        tail = temp;                    // set the temp as the tail
        temp = nullptr;
    }
    count  ;                            // increase the number of nodes
}

template <typename T>
void LinkedList<T>::AddNodesHead(const T* data, unsigned int count)
{
    for (unsigned int i = count-1; 1 <= i; i--)
    {
        AddHead(data[i]);
    }
}

template <typename T>
void LinkedList<T>::AddNodesTail(const T* data, unsigned int count)
{
    for (unsigned int i = 0; i <= count-1; i  )
    {
        AddTail(data[i]);
    }
}

template <typename T>
void LinkedList<T>::Clear()
{
    // Deletes all Nodes. Don’t forget the node count—how many nodes do you have after
    // you deleted all of them?
    
    Node* ptr = head;
    Node* temp;
    while (ptr != nullptr)
    {
        temp = ptr->next;
        delete ptr;
        ptr = temp;
    }
    head = nullptr;
    tail = nullptr;                     // set tail to null
    count = 0;                          // reset node count
}

template <typename T>
unsigned int LinkedList<T>::NodeCount() const
{
    return count;
}


template <typename T>
typename LinkedList<T>::Node* LinkedList<T>::Head()
{
    // Returns the head pointer. Const and non-const versions.
    return head;
}

template <typename T>
const typename LinkedList<T>::Node* LinkedList<T>::Head() const
{
    return head;
}

template <typename T>
typename LinkedList<T>::Node* LinkedList<T>::Tail()
{
    // Returns the tail pointer. Const and non-const versions.
    return tail;
}

template <typename T>
const typename LinkedList<T>::Node* LinkedList<T>::Tail() const
{
    return tail;
}

template <typename T>
void LinkedList<T>::PrintForward() const
{
    Node* temp = head;
    while (temp != nullptr)             // Iterator through all of the nodes and print out their values, one a time.
    {
        cout << temp->data << endl;
        temp = temp->next;
    }
    delete temp;
    temp = nullptr;
}

template <typename T>
void LinkedList<T>::PrintReverse() const
{
    Node* temp = tail;
    while (temp != nullptr)
    {
        cout << temp->data << endl;
        temp = temp->prev;
    }
    delete temp;
    temp = nullptr;
}

template <typename T>
LinkedList<T>::~LinkedList()
{
    // Destructor
    Clear();
}

CodePudding user response:

You didn't include the main. What you posted is just a class definition, which on its own does not leak. However, it is easy to come up with an example that leaks:

int main() {
    LinkedList<int> l;
}

Because you have in class initializers:

private: 
    Node* head = new Node;          // Node pointer for the head
    Node* tail = new Node;          // Node pointer for the tail
    unsigned int count;             // counting nodes in list
};

And then the default constructor throws away the pointers to the allocated Nodes and assigns nullptr:

template <typename T>
LinkedList<T>::LinkedList()
{
    // Default Constructor
    count = 0;
    head = nullptr;
    tail = nullptr;
}

The members are initialized before the body of the constructor runs and once the body of the constuctor runs you lost any reference to the allocated head and tail.

CodePudding user response:

This is a lot to digest, but at least one source of error here is likely that you have

class LinkedList
{
...
private:
    Node* head = new Node;          // Node pointer for the head
    Node* tail = new Node;          // Node pointer for the tail
    unsigned int count;   
}

And then in your constructor

LinkedList<T>::LinkedList()
{
    // Default Constructor
    count = 0;
    head = nullptr;
    tail = nullptr;
}

So you're causing the default initializer to invoke new, which is performing a heap allocation. And then in the constructor body, you overwrite these pointers with nullptr! This is immediately a leak, you now have no reference to those heap-allocated objects, and can't free the memory.

The first thing I would try here is to just change your header code to

class LinkedList
{
...
private:
    Node* head = nullptr;          // Node pointer for the head
    Node* tail = nullptr;          // Node pointer for the tail
    unsigned int count = 0;   
}

And then refactor your constructors (they no longer need to set the pointers to nullptr or your count to 0). Even better, for your default constructor you can then just declare it as

    // Default Constructor
    LinkedList() = default;
  • Related