Background
I have implemented a templated LinkedList structure. This structure serves as a single linked list and has an accompanying templated Node class. These two structures are working fine. However, the iterator I have been working on for a while is having some sort of "off by 1" error and seems to be falling off the end of the List.
Code
Here is the related code (Note: I am implementing other templated methods in a .inl file for the various templated classes. I am keeping the iterator code in the .hpp until I manage to get it running, at which point I can abstract it out. I do not believe this code structure has an impact whatsoever, but please correct me if I am wrong)
LiteNode.hpp
#ifndef LiteNode_H
#define LiteNode_H
#define nullptr 0
template<class LiteNodeType>
class LiteNode
{
private:
LiteNode* next;
public:
LiteNodeType data;
LiteNode(const LiteNodeType& data);
~LiteNode();
LiteNodeType getData(void) const;
void setNext(LiteNode* next);
LiteNode<LiteNodeType>* getNext(void);
};
#include "LiteNode.inl"
#endif
LinkedList.hpp
#include "Knight/DataStructures/LiteNode.hpp"
#include <iostream>
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
template<class type>
class LinkedList
{
private:
LiteNode<type>* head;
LiteNode<type>* tail;
int size;
public:
class Iterator
{
private:
friend class LinkedList;
LiteNode<type>* elementPtr;
public:
Iterator(LiteNode<type>& node)
{
elementPtr = &node;
}
Iterator(LiteNode<type>* node = nullptr)
{
elementPtr = node;
}
Iterator& operator++()
{
elementPtr = elementPtr->getNext();
return *this;
}
Iterator operator++(int a)
{
Iterator retval = *this;
++*this;
return retval;
}
type& operator*() const
{
type& retVal = elementPtr->data;
return retVal;
}
bool operator==(const Iterator& rhs) const
{
return elementPtr == rhs.elementPtr;
}
bool operator!=(const Iterator& rhs) const
{
bool retVal = elementPtr != rhs.elementPtr;
return retVal;
}
};
LinkedList();
~LinkedList();
void addElement(const type& element);
void reverse(void);
void deleteHeadElement(void);
void printData(void);
Iterator& start() const
{
return Iterator(this->head);
}
Iterator& end() const
{
return Iterator(this->tail);
}
};
#include "LinkedList.inl"
#endif
main.cpp
//Iterator testing
LinkedList<int>* testList = new LinkedList<int>();
testList->addElement(10);
testList->addElement(20);
testList->addElement(40);
testList->addElement(60);
for(LinkedList<int>::Iterator iter = testList->start(); iter != testList->end() ; iter++)
{
std::cout << *iter << std::endl;
}
What I Have Tried
The output I get when it oversteps the bounds is
10
20
40
60
So for some reason it is making it one over. I tried changing the main code to the following:
//Iterator testing
LinkedList<int>* testList = new LinkedList<int>();
testList->addElement(10);
testList->addElement(20);
testList->addElement(40);
testList->addElement(60);
LinkedList<int>::Iterator endIter = testList->end(); //<-- Main change
for(LinkedList<int>::Iterator iter = testList->start(); iter != endIter ; iter++)
{
std::cout << *iter << std::endl;
}
and I get the following output(with no crash):
10
20
40
I tried setting watches on the various iteration pointers and elementPtr variables to see what is happening and I noticed that when I use testList->end() in the comparison part of the for loop the value of its "elementPtr" changes to 0xcccccccc or some other trash value like that. I tried tinkering with the increment functions thinking those may be tweaking some value I did not want it to but it has not gotten me anywhere.
I really think that I am close here and there is some tiny error here that is messing with something. I was hoping some extra eyes could help spot a problem.
Solution (EDIT)
Alright, so Molbdnilo pointed out a key piece of what I was doing wrong. Read his answer for the first part of the solution. Something I had to do in addition to what he mentioned is pass something I knew would be null in order to produce the "Theoretical last element" from the end() function. Here is an std::vector<> page talking about this: http://www.cplusplus.com/reference/vector/vector/end/ This allows me to cycle through all of the elements and not miss the last one which was my problem once I fixed my Iterator() return types as mentioned below. Here is the code I modified to make it work:
Iterator start() const
{
return Iterator(this->head);
}
Iterator end() const
{
return Iterator(this->tail->getNext());
}