C++ Linked List Iterator Class - c++

I created a singly linked list for a project and now need to create a custom Iterator class. I have a nested class within my Linked List that defines my iterator. I have written most of the class, but am confused as to how to implement some functions. My issues are as follows:
-Please look at my end() function. I set it to the default constructor for the Iterator class, so the
currentNode variable in iterator got defaulted to NULL I guess. Is this correctly implemented?
-How should I overload the -> operator in the Iterator class?
class SSLL_Iter : public std::iterator<std::forward_iterator_tag, T>
{
public:
typedef T value_type;
typedef std::ptrdiff_t difference_type;
typedef T& reference;
typedef T* pointer;
typedef std::forward_iterator_tag iterator_category;
typedef SSLL_Iter self_type;
typedef SSLL_Iter& self_reference;
private:
Node* currentNode;
public:
explicit SSLL_Iter( Node* start = NULL) : currentNode( start ) {} //****************complete
SSLL_Iter( const SSLL_Iter& src ) : currentNode( src.currentNode ) {} //****************complete
reference operator*() const { //****************complete
T& temp = (currentNode->data);
return temp;
}
pointer operator->() const {} //*******??????????????????
self_reference operator=( const SSLL_Iter& src ) { //****************complete
this->here = src.here;
return *this;
}
self_reference operator++() { // preincrement //****************complete
currentNode = currentNode->next;
return *this;
}
self_type operator++(int) { // postincrement //****************complete
self_type temp = (*this);
++(*this);
return temp;
}
bool operator==(const SSLL_Iter& rhs) const { //****************complete
return (this->currentNode == rhs.currentNode);
}
bool operator!=(const SSLL_Iter& rhs) const { //****************complete
return (this->currentNode != rhs.currentNode);
}
}; // end SSLL_Iter
typedef std::size_t size_t;
typedef T value_type;
typedef SSLL_Iter iterator;
//typedef Const_SSL_Iter const_iterator;
SSLL() {}
SSLL(const SSLL& src ) {
for(int i = 0; i < src.size(); ++i) { // populate this SSLL with copies of the other SSLL's contents
this->push_back(src.item_at(i));
}
}
~SSLL() {
if(!is_empty()) {
clear();
}
}
iterator begin() { return SSLL_Iter( head ); }
iterator end() { return SSLL_Iter(); }

return &*(*this); is a decent operator->.
Your SSLL class probably does not have an efficient at, so don't use it in the copy constructor. Instead, create a SSLL template<class Iterator> void append(Iterator s, Iterator f), and implement SSLL(const SSLL& src) in terms of it.
If you have C++11 support, consider replacing the next node of Node with a std::unique_ptr<Node>. Do the same with the pointer-to-first Node in the SSLL root. Now memory management is handled pretty much automatically. You may need a .get() in your iterator after that change. This also eliminates the body of your destructor, makes your move-constructor =default correct (unless you are counting nodes), etc.

Related

Custom iterator for the Matrix class

I wrote my own matrix class with fields like this
template <typename T>
class Matrix
{
private:
T *data = nullptr;
size_t rows;
size_t cols;
....
I tried to make an iterator for my matrix, but it didn't work. An error like this is thrown in method Iterator begin(and end):
error: cannot convert ‘myMatrix::Matrix<int>::Iterator’ to ‘int*’ in return
The iterator must support STL functions such as std::find_if(). How can I fix the iterator so that it works correctly?
class Iterator
{
friend Matrix;
private:
T *curr;
public:
using iterator_category = std::input_iterator_tag;
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = value_type *;
using reference = value_type &;
Iterator() : curr(nullptr) {}
Iterator(T *other) : curr(other) {}
~Iterator() = default;
bool operator==(const Iterator &it) const { return curr == it.curr; }
bool operator!=(const Iterator &it) const { return !(curr == it.curr); }
Iterator &operator++()
{
++curr;
return *this;
}
Iterator operator++(int)
{
Iterator temp = *this;
operator++();
return temp;
}
Iterator &operator+(int n)
{
for (int i = 0; i < n; i++)
{
++(*this);
}
return *this;
}
T &operator*() const { return *curr; }
T *operator->() const { return curr; }
};
Iterator begin()
{
Iterator it(data);
return it;
}
Iterator end()
{
Iterator it(data + rows * cols);
return it;
}

Implement iterator for std::uniqe_ptr Linked list

This is my code so far, it obviously does not work. I want this iterator to work on
both range and increment based for loops. How can I do it?
template<typename T>
class MyList {
public:
class Node {
public:
Node(const T& data): data(data) {
this->next = NULL;
}
std::unique_ptr<Node> next;
T data;
};
MyList() {
this->_size = 0;
}
int size() const;
void push_front(const T& data);
T pop_front();
T front() const;
void remove(T data);
typedef T* iterator;
typedef const Node* const_iterator;
iterator begin() {
return (&_head.get()->data);
}
iterator end() {
return (NULL);
}
private:
int _size;
std::unique_ptr<MyList<T>::Node> _head;
};
T* is not suitable as a linked-list iterator, as it has no way to get to the next node in the list when incremented. Also because &_head.get()->data is not valid when the list is empty.
And Node* will not work for either iterator or const_iterator, either, since it can't have a valid operator++ to iterator the list, or anoperator* to access the data. See the requirements for a ForwardIterator.
You are better off defining a separate type to act as a (const_)iterator and let it hold a Node* internally for iterating and dereferencing, eg:
template<typename T>
class MyList {
public:
class Node {
public:
Node(const T& data): data(data) {}
std::unique_ptr<Node> next;
T data;
};
template<typename D>
class my_iterator
{
public:
my_iterator(Node* node) : _current(node) {}
bool operator==(const my_iterator &rhs) const { return _current == rhs._current; }
D& operator*() { return _current->data; }
D* operator->() { return &(_current->data); }
my_iterator& operator++() { _current = _current->next.get(); return *this; }
my_iterator operator++(int) { my_iterator tmp(_current); ++(*this); return tmp; }
private:
Node* _current;
};
using iterator = my_iterator<T>;
using const_iterator = my_iterator<const T>;
...
iterator begin() {
return iterator(_head.get());
}
const_iterator cbegin() const {
return const_iterator(_head.get());
}
iterator end() {
return iterator(nullptr);
}
const_iterator cend() const {
return const_iterator(nullptr);
}
...
};

linked list with unique pointers being used as type

I'm having a problem getting my linked list (it's actually a square list) passing tests that have been given by my professor, and I'm not sure what I'm supposed to do.
Here's my code:
/** LinkedList class declaration. */
template <typename T>
class LinkedList;
template <class TNode>
class Iterator
{
/* Helper class to provide pointer like facilities around a node */
friend class LinkedList<typename TNode::value_type>;
TNode* pNode; //The node oriented with this instance of iterator.
//Iterator(TNode* _pNode) : pNode(_pNode) {}
public:
Iterator(TNode* _pNode) : pNode(_pNode) {}
using value_type = typename TNode::value_type;
//using size_type = std::size_type;
using pointer = TNode*;
using difference_type = std::ptrdiff_t;
using reference = value_type&;
using iterator = Iterator<TNode>;
using iterator_category = std::bidirectional_iterator_tag;
.............removed unneeded code...............
value_type get() {
return pNode->_data;
}
typename TNode::value_type &operator*(){ return pNode->_data; }
};
template <typename T>
class Node
{
friend class LinkedList<T>;
friend class Iterator<Node<T> >;
Node() : _next(0), _prev(0), _head(0), _nextHead(0), _prevHead(0) {}
Node(T data) : _data(data), _next(0), _head(0), _nextHead(0), _prevHead(0) {}
Node(T data, Node<T>* next, Node<T>* prev, Node<T>* head, Node<T> nextHead, Node<T> prevHead) :
_data(data), _next(next), _prev(prev), _head(head), _nextHead(nextHead), _prevHead(prevHead){}
T _data;
Node<T>* _next;
Node<T>* _prev;
Node<T>* _head;
Node<T>* _nextHead;
Node<T>* _prevHead;
public:
typedef T value_type;
};
template <typename T>
class LinkedList
{
public:
using size_type = std::size_t;
private:
Node<T>* first;
Node<T>* last;
Node<T>* lastHead;
size_type _count = 0;
double columnNumbers = 0;
public:
typedef T value_type;
using pointer = std::unique_ptr<Node<T>>;
using iterator = Iterator<Node<T>>;
using difference_type = std::ptrdiff_t;
using reference = T&;
using const_reference = T const&;
using const_pointer = T const*;
using const_iterator = iterator const;
using reverse_iterator = std::reverse_iterator < iterator >;
using const_reverse_iterator = reverse_iterator const;
LinkedList() : first(0), last(0), lastHead(0) { }
~LinkedList()
{
.............removed unneeded code...............
}
iterator begin(){ return iterator(first); }
iterator end(){ return iterator(last); }
const_iterator begin() const { return const_iterator(first); }
const_iterator end() const { return const_iterator(last); }
const_iterator cbegin() const { return const_iterator(first); }
const_iterator cend() const { return const_iterator(last); }
reverse_iterator rbegin() { return reverse_iterator(last); }
reverse_iterator rend() { return reverse_iterator(first); }
const_reverse_iterator rbegin() const { return const_reverse_iterator(last); }
const_reverse_iterator rend() const { return const_reverse_iterator(first); }
const_reverse_iterator crbegin() const { return const_reverse_iterator(last); }
const_reverse_iterator crend() const { return const_reverse_iterator(first); }
.............removed unneeded code...............
void insert(T data)
{
.............removed unneeded code...............
}
void reorder() { // this reorders the head pointers so they are all in the correct spot for the square list
.............removed unneeded code...............
}
bool erase(iterator& _iNode) //True for success, vice versa
{
.............removed unneeded code...............
}
void clear()
{
.............removed unneeded code...............
}
};
template <typename T>
bool operator==(Iterator<Node<T>> const& lhs, Iterator<Node<T>> const& rhs){
return lhs.compare(rhs);
}
Here's the test I am supposed to run
BOOST_AUTO_TEST_CASE(ut_Rvalue_insert_scrambled_int) {
typedef std::unique_ptr<int> UP;
std::vector<int> data{ 9, 10, 7, 8, 5, 6, 3, 4, 1, 2 };
LinkedList<UP> sqi;
for (auto datum : data) {
sqi.insert(UP(new int(datum)));
}
std::sort(data.begin(), data.end());
std::vector<int> dup;
for (auto iter = sqi.begin(); iter != sqi.end(); ++iter) {
dup.push_back(*iter->get());
}
std::sort(data.begin(), data.end());
std::sort(dup.begin(), dup.end());
BOOST_CHECK(dup.size() == data.size());
BOOST_CHECK_EQUAL_COLLECTIONS(dup.begin(), dup.end(), data.begin(), data.end());
}
When compiling, I get these errors:
Error 1 error C2819: type 'Iterator<Node<T>>' does not have an overloaded member 'operator ->' ut_square_list_10_insert_rvalue.cpp 33
and
Error 2 error C2232: '->Iterator<Node<T>>::get' : left operand has 'class' type, use '.' ut_square_list_10_insert_rvalue.cpp 33 1
So, I know this is an issue relating to pointers, but I don't know how, or what I should be doing here.
In particular, it's this line...
dup.push_back(*iter->get());
Is there a better way to set this up, or is he requiring me to overload the -> operator?
I tried changing it to this (even though my prof will not want it this way -- he rips the current ut files out and puts fresh copies in, so he wants it to work the above way, and not this way)
dup.push_back(*iter.get());
It no longer gives me the overloaded errors, but is it giving me this now:
Error 1 error C2280: 'std::unique_ptr<int,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : attempting to reference a deleted function
Ok, lets look at the types here.
You have a LinkedList<UP> and std::vector<int>.
So when you're trying to push an element to vector using list's iterator, you have to get a UP value from iterator using iter.get(), and then dereference it using operator *.
So the final line should look like this:
dup.push_back(*iter.get());
Now that this project has been submitted and marked, I thought I would give the answer.
value_type *operator->() const {
TNode* node = pNode;
value_type* nodeData = &node->_data;
return nodeData;
}
Essentially, from what I understand, and the way I created my linked list, I needed to overload the -> operator and pass out a pointer to the data reference.
If someone could explain this a bit more I would really appreciate it. It's tough to wrap my head around why I would need to do this, but this is the only way I could figure out how to achieve this, and was the accepted answer by the prof (I didn't lose any marks on the project).

correctly implementing iterators for custom class without using boost

I have made a LinkedList class. This is a singly-linked-list and I want to make a forward_iterator for this class. I have made the code and i want to know whether i have implemented it correctly. The source i referred to make this code is here.
template <class T>
struct node
{
T data;
node *next;
};
template <class T>
class LinkedList
{
private :
node<T> *start;
unsigned int numElements;
// Assume all functions are implemented
};
Iterator Code :
class iterator : public std::iterator<std::forward_iterator_tag,node<T>*>
{
node<T>* itr;
public :
iterator (node<T>* temp) : itr(temp) {}
iterator (const iterator& myitr) : itr(myitr.itr) {}
iterator& operator++ ()
{
itr = itr->next;
return *this;
}
bool operator== (const iterator& rhs)
{
return itr == rhs.itr;
}
bool operator!= (const iterator& rhs)
{
return itr != rhs.itr;
}
T& operator*()
{
return itr->data;
}
};
Q. Is the above implementation correct ?
Q. If no then what changes should i make ? Also do any additional thing needs to implemented ?
I'll assume that the missing parentheses in
iterator& operator++
are a typo (still, the compiler needs them there). Then you're only missing two things:
the postfix ++ operator
the -> operator
So:
iterator operator++(int) {
iterator result(*this);
++*this;
return result;
}
T *operator->() {
return &itr->data;
}
...and then you have fulfilled all requirements of the ForwardIterator concept.

struct reference and operator=

I have a class like this:
template <class T>
class bag
{
private:
typedef struct{T item; unsigned int count;} body;
typedef struct _node{_node* prev; body _body; _node* next;}* node;
struct iterator{
enum exception{NOTDEFINED, OUTOFLIST};
body operator*();
explicit iterator();
explicit iterator(const iterator&);
iterator& operator=(const iterator&);
iterator& operator++(int);
iterator& operator--(int);
bool operator==(const iterator&) const;
bool operator!() const;
private:
node current;
friend class bag;
};
node head;
node foot;
iterator _begin;
iterator _end;
/* ... */
public: /* ... */
bag();
const iterator& begin;
const iterator& end;
};
In the bag() I have to set the reference begin to _begin, and end to _end.
begin = _begin;
end = _end;
But I think this line
begin = _begin;
invokes bag::iterator::operator=() function.
How can i avoid that?
References can't be assigned, only initialised. So you will need to initialise them in the constructor's initialisation list:
bag() : begin(_begin), end(_end) {}
However, it's more conventional (and also reduces the class size) to get these using accessor functions rather than public references:
const iterator& begin() {return _begin;}
const iterator& end() {return _end;}
Use initializer list:
bag::bag() : begin(begin_), end(end_)
{
}
As Mike said, you have to initialise a reference where you declare it, you can't change it afterwards. The initialiser list is the most idiomatic solution if you don't have to modify the references once the object is constructed, but in the case you foresee you have to change them, there are still the good old pointers:
public: /* ... */
bag();
iterator *begin;
iterator *end;
A class containing reference members essentially becomes unassignable (because references can't be reseated).
It looks like your Bag is duplicating the same data in several members (extra burden to keep duplicated values in synch).
Instead you could do what the standard library does: create and return the iterator by value from begin() and end() methods.
template <class T>
class bag
{
struct node { /*...*/ }
/* ... */
node* head; //why would you want to typedef away that these are pointers?
node* tail;
public:
class iterator {
iterator(node*);
/* ... */
};
iterator begin() { return iterator(head); }
iterator end() { return iterator(tail); }
//also you might need const_iterators
};