Here is a first attempt at iterator of a doubly linked list:
dlist.h
#ifndef dlist_h
#define dlist_h
/* Node */
template <class Elem>
struct Link
{
Link();
Link (Link<Elem>* s, Link<Elem>* p, const Elem& v);
Link (const Link<Elem>& src);
Link<Elem>& operator= (const Link<Elem>& src);
bool operator== (const Link<Elem>& src);
bool operator!= (const Link<Elem>& src);
void swap(Link<Elem>& src);
Link* succ;
Link* prev;
Elem val;
};
//----------------------------------------------------------------------------
/* Doubly Linked List */
template <class Elem>
class List
{
public:
class iterator;
List();
iterator begin() { return iterator(first, first, last); }
iterator end() { return iterator(last, first, last); }
void push_front(const Elem& v);
Elem& front();
size_t size();
void print();
private:
Link<Elem> *first;
Link<Elem> *last;
};
//----------------------------------------------------------------------------
/* a range-checked bidirectional iterator */
template <class Elem>
class List<Elem>::iterator
{
public:
iterator(); // default constructor
iterator(Link<Elem>* c, Link<Elem>* b, Link<Elem>* e);
iterator(const iterator& src); // copy constructor
iterator operator= (const iterator& src); // copy assignment
iterator& operator++(); // incrementations
iterator operator++(int); // postfix
iterator& operator--(); // decrementations
iterator operator--(int); // postfix
Elem& operator*(); // dereferenceable lvalue
const Elem& operator*() const; // dereferenceable rvalue
bool operator== (const iterator& b) const; // equality comparisons
bool operator!= (const iterator& b) const;
void swap(iterator& src);
private:
Link<Elem>* curr;
Link<Elem>* begin;
Link<Elem>* end;
};
#include "dlist.cpp"
#endif
dlist.cpp
//-----------------------------------------------------------------------------
template <class Elem>
Link<Elem>::Link()
: succ(nullptr), prev(nullptr), val(Elem())
{
}
//-----------------------------------------------------------------------------
template <class Elem>
Link<Elem>::Link (Link<Elem>* s, Link<Elem>* p, const Elem& v)
: succ(s), prev(p), val(v)
{
}
//-----------------------------------------------------------------------------
template <class Elem>
Link<Elem>::Link (const Link<Elem>& src)
: succ(src.succ), prev(src.prev), val(src.val)
{
}
//-----------------------------------------------------------------------------
template <class Elem>
Link<Elem>& Link<Elem>::operator= (const Link<Elem>& src)
{
Link<Elem> temp(src);
swap(*this, temp);
return *this;
}
//-----------------------------------------------------------------------------
template <class Elem>
bool Link<Elem>::operator== (const Link<Elem>& src)
{
return succ = src.succ && prev = src.prev;
}
//-----------------------------------------------------------------------------
template <class Elem>
bool Link<Elem>::operator!= (const Link<Elem>& src)
{
return !(*this == src);
}
//-----------------------------------------------------------------------------
template <class Elem>
void Link<Elem>::swap(Link<Elem>& src)
{
std::swap(prev, src.prev);
std::swap(succ, src.succ);
std::swap(val, src.val);
}
//-----------------------------------------------------------------------------
template<class Elem>
void swap(Link<Elem>& lhs, Link<Elem>& rhs)
{
lhs.swap(rhs);
}
//-----------------------------------------------------------------------------
template<class Elem>
List<Elem>::List()
: first(new Link<Elem>()), last(first)
{
}
//-----------------------------------------------------------------------------
template<class Elem>
void List<Elem>::push_front(const Elem& v)
{
first = new Link<Elem>(first, nullptr, v);
}
//-----------------------------------------------------------------------------
template<class Elem>
Elem& List<Elem>::front()
{
return first->val;
}
//-----------------------------------------------------------------------------
template<class Elem>
size_t List<Elem>::size()
{
size_t count = 0;
for (iterator p = begin(); p != end(); ++p)
{
++count;
}
return count;
}
//-----------------------------------------------------------------------------
template<class Elem>
void List<Elem>::print()
{
for (iterator p = begin(); p != end(); ++p)
{
std::cout << *p <<' ';
}
}
//-----------------------------------------------------------------------------
template<class Elem>
List<Elem>::iterator::iterator()
: curr(nullptr), begin(nullptr), end(nullptr)
{
}
//-----------------------------------------------------------------------------
template<class Elem>
List<Elem>::iterator::iterator(Link<Elem>* p, Link<Elem>* b, Link<Elem>* e)
: curr(p), begin(b), end(e)
{
}
//-----------------------------------------------------------------------------
template<class Elem>
List<Elem>::iterator::iterator(const iterator& src)
: curr(src.curr), begin(src.begin), end(src.end)
{
}
//-----------------------------------------------------------------------------
template<class Elem>
typename List<Elem>::iterator List<Elem>::iterator::operator= (const iterator& src)
{
iterator temp(src);
this->swap(temp);
return *this;
}
//-----------------------------------------------------------------------------
template<class Elem>
typename List<Elem>::iterator& List<Elem>::iterator::operator++()
{
if (curr == end)
{
throw std::out_of_range("List<Elem>::iterator::operator++(): out of range!\n");
}
curr = curr->succ;
return *this;
}
//-----------------------------------------------------------------------------
template<class Elem>
typename List<Elem>::iterator List<Elem>::iterator::operator++(int)
{
if (curr == end)
{
throw std::out_of_range("List<Elem>::iterator::operator++(): out of range!\n");
}
Link<Elem>* old = curr;
curr = curr->succ;
return old;
}
//-----------------------------------------------------------------------------
template<class Elem>
typename List<Elem>::iterator& List<Elem>::iterator::operator--()
{
if (curr == begin)
{
throw std::out_of_range("List<Elem>::iterator::operator--(): out of range!\n");
}
curr = curr->prev;
return *this;
}
//-----------------------------------------------------------------------------
template<class Elem>
typename List<Elem>::iterator List<Elem>::iterator::operator--(int)
{
if (curr == begin)
{
throw std::out_of_range("List<Elem>::iterator::operator--(): out of range!\n");
}
iterator old(*this);
curr = curr->prev;
return old;
}
//-----------------------------------------------------------------------------
template<class Elem>
Elem& List<Elem>::iterator::operator*()
{
return curr->val;
}
//-----------------------------------------------------------------------------
template<class Elem>
const Elem& List<Elem>::iterator::operator*() const
{
return curr->val;
}
//-----------------------------------------------------------------------------
template<class Elem>
bool List<Elem>::iterator::operator== (const iterator& b) const
{
return curr == b.curr;
}
//-----------------------------------------------------------------------------
template<class Elem>
bool List<Elem>::iterator::operator!= (const iterator& b) const
{
return curr != b.curr;
}
//-----------------------------------------------------------------------------
template<class Elem>
void List<Elem>::iterator::swap(iterator& src)
{
std::swap(curr, src.curr);
std::swap(begin, src.begin);
std::swap(end, src.end);
}
//-----------------------------------------------------------------------------
template<class Elem>
void swap(typename List<Elem>::iterator& lhs, typename List<Elem>::iterator& rhs)
{
lhs.swap(rhs);
}
main.cpp
#include <iostream>
#include "dlist.h"
/* simple test for iterator */
int main()
{
List<int> l;
l.push_front(1);
l.push_front(2);
l.push_front(3);
l.push_front(4);
l.push_front(5);
// default constructor, copy assignment
List<int>::iterator p = l.begin();
// lvalue dereferencing
*p = 100;
// incrementation, rvalue dereferencing
List<int>::iterator i;
for (i = l.begin(); i != l.end(); ++i)
{
std::cout << *i <<' ';
}
if (i == l.end() && i != l.begin())
{
std::cout <<"\ncomparison correct!\n";
}
// postfix and prefix decrementation; maintain dereferenceability
List<int>::iterator ii = l.end();
--ii;
for (; ii != l.begin(); ii--)
{
std::cout << *ii <<' ';
}
return 0;
}
When it reaches the last for
loop the decrement operator--
somehow invalidates the ii
iterator and I can't figure it out despite a thoroughIMO debugging.
Here is a runnable sample.