Frage

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());
}
War es hilfreich?

Lösung

This is returning a reference to a temporary object, an operation that is undefined:

Iterator& start() const
{
    return Iterator(this->head);
}

The object you're attempting to return a reference to is destroyed when the function exits.

You shouldn't have a reference there:

Iterator start() const
{
    return Iterator(this->head);
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top