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;
