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 Node
s 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;