C++ List Implementation - c++

So, I'm building an implementation of List for a programming exercise. So far I have this:
#include <iostream>
#include <algorithm>
using namespace std;
template <class T> class Link;
template <class T> class List_iterator;
template <class T>
class List
{
public:
typedef List_iterator<T> iterator;
List();
List(const List<T> & l);
~List();
bool empty() const;
unsigned int size() const;
T & back() const;
T & front() const;
void push_front(const T & x);
void push_back(const T & x);
void pop_front();
void pop_back();
iterator begin() const;
iterator end() const;
void insert(iterator pos, const T & x);
void erase(iterator & pos);
List<T> & operator=(const List<T> & l);
protected:
Link<T> * first_link;
Link<T> * last_link;
unsigned int my_size;
};
template <class T>
List<T>::List()
{
first_link = 0;
last_link = 0;
my_size = 0;
}
template <class T>
List<T>::List(const List & l)
{
first_link = 0;
last_link = 0;
my_size = 0;
for (Link<T> * current = l.first_link; current != 0; current = current -> next_link)
push_back(current -> value);
}
template <class T>
typename List<T>::iterator List<T>::begin() const
{
return iterator(first_link);
}
template <class T>
class Link
{
private:
Link(const T & x): value(x), next_link(0), prev_link(0) {}//pg. 204
T value;
Link<T> * next_link;
Link<T> * prev_link;
friend class List<T>;
friend class List_iterator<T>;
};
template <class T> class List_iterator
{
public:
typedef List_iterator<T> iterator;
List_iterator(Link<T> * source_link): current_link(source_link) { }
List_iterator(): current_link(0) { }
List_iterator(List_iterator<T> * source_iterator): current_link(source_iterator.current_link) { }
T & operator*(); // dereferencing operator
iterator & operator=(const iterator & rhs);
bool operator==(const iterator & rhs) const;
bool operator!=(const iterator & rhs) const;
iterator & operator++();
iterator operator++(int);
iterator & operator--();
iterator operator--(int);
protected:
Link<T> * current_link;
friend class List<T>;
};
template <class T>
T & List_iterator<T>::operator*()
{
return current_link -> value;
}
template <class T>
List_iterator<T> & List_iterator<T>::operator++()
{
current_link = current_link -> next_link;
return *this;
}
template <class T>
void List<T>::push_back(const T & x)
{
link<T> * last_link = new link<T> (x);
if (empty())
first_link = last_link;
else
{
last_link->prev_link = last_link;
last_link->prev_link = last_link;
last_link = last_link;
}
}
template <class T>
typename List<T>::iterator List<T>::end() const
{
return iterator(last_link);
}
int main()
{
List<int> l;
l.push_back(44); // list = 44
l.push_back(33); // list = 44, 33
l.push_back(11); // list = 44, 33, 11
l.push_back(22); // list = 44, 33, 11, 22
List<int> m(l);
List<int>::iterator itr(m.begin());
while (itr != m.end()) {
cout << *itr << endl;
itr++;
}
}`
I'm having a lot of trouble with my push_back() function and I'm not quite sure what's wrong. Can anyone point out my errors?
Updated Code In Progress:
#include <iostream>
#include <algorithm>
using namespace std;
template <class T> class Link;
template <class T> class List_iterator;
template <class T>
class List
{
public:
typedef List_iterator<T> iterator;
List();
List(const List<T> & l);
~List();
bool empty() const;
unsigned int size() const;
T & back() const;
T & front() const;
void push_front(const T & x);
void push_back(const T & x);
void pop_front();
void pop_back();
iterator begin() const;
iterator end() const;
void insert(iterator pos, const T & x);
void erase(iterator & pos);
List<T> & operator=(const List<T> & l);
protected:
Link<T> * first_link;
Link<T> * last_link;
unsigned int my_size;
};
template <class T>
List<T>::List()
{
first_link = 0;
last_link = 0;
my_size = 0;
}
template <class T>
List<T>::List(const List & l)
{
first_link = 0;
last_link = 0;
my_size = 0;
for (Link<T> * current = l.first_link; current != 0; current = current -> next_link)
push_back(current -> value);
}
template <class T>
typename List<T>::iterator List<T>::begin() const
{
return iterator(first_link);
}
template <class T>
class Link
{
private:
Link(const T & x): value(x), next_link(0), prev_link(0) {}//pg. 204
T value;
Link<T> * next_link;
Link<T> * prev_link;
friend class List<T>;
friend class List_iterator<T>;
};
template <class T> class List_iterator//pg.207
{
public:
typedef List_iterator<T> iterator;
List_iterator(Link<T> * source_link): current_link(source_link) { }
List_iterator(): current_link(0) { }
List_iterator(List_iterator<T> * source_iterator): current_link(source_iterator.current_link) { }
T & operator*(); // dereferencing operator
iterator & operator=(const iterator & rhs);
bool operator==(const iterator & rhs) const;
bool operator!=(const iterator & rhs) const;
iterator & operator++();
iterator operator++(int);
iterator & operator--();
iterator operator--(int);
protected:
Link<T> * current_link;
friend class List<T>;
};
template <class T>
T & List_iterator<T>::operator*()
{
return current_link -> value;
}
template <class T>
List_iterator<T> & List_iterator<T>::operator++()
{
current_link = current_link -> next_link;
return *this;
}
template <class T>
void List<T>::push_back(const T & x)
{
Link<T> * new_link = new Link<T> (x);
if (first_link = 0)
first_link = last_link = new_link;
else
{
new_link->prev_link = last_link;
last_link->next_link = new_link;
last_link = new_link;
}
my_size++;
}
template <class T>
typename List<T>::iterator List<T>::end() const
{
return iterator(last_link);
}
template <class T>
List <T>::~List()
{
Link <T> * first = first_link;
while (first != 0)
{
Link <T> * next = first->next_link;
delete first;
first = next;
}
}
template<class T>
bool List_iterator<T>::operator==(const iterator & rhs) const
{
return ( this->current_link == rhs.current_link );
}
template <class T>
bool List_iterator<T>::operator!=(const iterator & rhs) const
{
return !( *this == rhs );
}
int main()
{
List<int> l;
l.push_back(44); // list = 44
l.push_back(33); // list = 44, 33
l.push_back(11); // list = 44, 33, 11
l.push_back(22); // list = 44, 33, 11, 22
List<int> m(l);
List<int>::iterator itr(m.begin());
while (itr != m.end()) {
cout << *itr << endl;
++itr;
}
}

Mario's and Joe's answers are both valid (I would vote them up if I could).
Issue 1
Assuming that what you posted is your ACTUAL code for push_back() then Link<T> has the wrong case.
link<T> * last_link = new link<T> (x);
...should be:
Link<T> * last_link = new Link<T> (x);
Doing this gets rid of error: expected primary-expression before ‘>’ token (when compiled with g++)
Issue 2
An alternative to what Mario and Joe suggested, is to NOT hide your List<T>'s last_link. Use a temporary variable that does NOT have the same name as your class's data member. Change:
Link<T> * last_link = new Link<T> (x);
...to...
Link<T> * new_link = new Link<T> (x);
This will make your code clearer and you will be referencing the right node.
Issue 3
Following the above steps should make two logic errors in push_back() evident. I'm willing to assist, but I'm sure you will see it.

The following line creates a local variable named last_link inside push_back().
link<T> * last_link = new link<T> (x);
Referencing last_link after this will point to this local variable instead of the class member. You'll have to add this-> in front of the class ones, e.g. this->last_link = last_link;.

You have a local variable that is the same as a member variable name. When you're using last_link you're using the one that you just created in the push_back function. You're also assigning last_link->prev_link twice. Then also assigning last_link = last_link. I'd either change the name of the local variable, or add this-> in front of it.

Related

Restruct list iterator after erase

I've created a custom Node, Iterator and List.
I would like to do:
List<int> list;
// push_back objects here...
List<int>::Iterator it = list.begin();
list.erase(it);
++it;
list.erase(it); // error here
So I need to reconstruct the iterator after erasing an element. How do I do that?
Node.h
#pragma once
namespace Util
{
template<typename T>
class Node
{
public:
template<typename T> friend class Iterator;
template<typename T> friend class List;
private:
Node();
Node(T);
~Node();
/* unlink(): takes out this node
and links next and prev to each other
prev <- this -> next
prev <- -> next
this <- this -> this
*/
void unlink();
private:
T value;
Node<T>* next;
Node<T>* prev;
};
template<typename T>
Node<T>::Node() : next(this), prev(this)
{
// ...
}
template<typename T>
Node<T>::Node(T t) : value(t), next(this), prev(this)
{
// ...
}
template<typename T>
Node<T>::~Node()
{
unlink();
}
template<typename T>
void Node<T>::unlink()
{
next->prev = prev;
prev->next = next;
next = this;
prev = this;
}
}
Iterator.h
#pragma once
#include "Node.h"
namespace Util
{
template<typename T>
class Iterator
{
public:
template<typename T> friend class List;
Iterator& operator++();
T& operator*() const;
bool operator==(const Iterator& rhs) const;
bool operator!=(const Iterator& rhs) const;
private:
Iterator(Node<T>* n);
Node<T>* node;
};
template<typename T>
Iterator<T>::Iterator(Node<T>* n) : node(n)
{
// ...
}
template<typename T>
Iterator<T>& Iterator<T>::operator++()
{
node = node->next;
return *this;
}
template<typename T>
T& Iterator<T>::operator*() const
{
return node->value;
}
template<typename T>
bool Iterator<T>::operator==(const Iterator& rhs) const
{
return node == rhs.node;
}
template<typename T>
bool Iterator<T>::operator!=(const Iterator& rhs) const
{
return node != rhs.node;
}
}
List.h
#pragma once
#include "Iterator.h"
namespace Util
{
template<typename T>
class List
{
public:
typedef Iterator<T> Iterator;
typedef Node<T> Node;
List();
~List();
// Capacity
bool empty() const;
int size() const;
// Modifiers
void push_back(const T&);
void push_front(const T&);
void pop_back();
void pop_front();
Iterator erase(Iterator it);
// Element access
Iterator begin() const;
Iterator end() const;
private:
Node* head;
int list_size;
};
template<typename T>
List<T>::List() : list_size(0)
{
head = new Node();
}
template<typename T>
List<T>::~List()
{
while (!empty()) pop_back();
delete head;
}
template<typename T>
bool List<T>::empty() const
{
return head->next == head;
}
template<typename T>
int List<T>::size() const
{
return list_size;
}
template<typename T>
void List<T>::push_back(const T& t)
{
Node* n = new Node(t);
n->next = head;
n->prev = head->prev;
head->prev->next = n;
head->prev = n;
++list_size;
}
template<typename T>
void List<T>::push_front(const T& t)
{
Node* n = new Node(t);
n->prev = head;
n->next = head->next;
head->next->prev = n;
head->next = n;
++list_size;
}
template<typename T>
void List<T>::pop_back()
{
if (head->prev == head) return;
delete head->prev;
--list_size;
}
template<typename T>
void List<T>::pop_front()
{
if (head->next == head) return;
delete head->next;
--list_size;
}
template<typename T>
typename List<T>::Iterator List<T>::erase(Iterator it)
{
if (it.node == head) return it;
Node* n = it.node->next;
delete it.node;
--list_size;
return Iterator(n);
}
template<typename T>
typename List<T>::Iterator List<T>::begin() const
{
return Iterator(head->next);
}
template<typename T>
typename List<T>::Iterator List<T>::end() const
{
return Iterator(head);
}
}
Edit: after updating the code based on the comments I received. Going through the list and erasing, only erases every other element; since the loop is incrementing the iterator and erase makes the iterator's current object iterator's next object. Is this how it is in the standard as well?
for (Util::List<int>::Iterator it = list.begin(); it != list.end(); ++it)
{
it = list.erase(it);
}
Old list: 0 1 2 3 4 5 6 7 8 9
After erasing: 1 3 5 7 9
Please do not complain about rule of five and things unrelated to the question. I haven't gotten to every part yet. My justification of making an edit over posting a new question is that the edit is still about how to reconstruct the iterator correctly after erase.
As some people already mentioned, erase typically returns a new, valid iterator, if that is possible/feasible for the container.
You can define the semantics as you would like, but typically you would erase the element by pointing prev->next to next and next->prev to prev, then deallocate the node, and return an iterator to next. You could also return an iterator to prev, but that results in several counter-intuitive behaviors, such as having to advance the iterator if you are doing an operation on some sort of range. Returning an iterator to next, just lets you delete ranges with while(foo(it)) it = c.erase(it);
In that case you of course don't increment the iterator anymore, unless you wan t to skip every other element.

Not maintaining iterator dereferenceability?

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.
The problem is your push_front method, you forgot to link first->succ->prev back to new node, hence your doubly linked list is basically a singly linked list
The first i-- succeed because last points to a default node, but curr->prev is a nullptr since you forgot to link back, so the next i-- will deref the nullptr curr cause the error.
Fix your push_front method:
template<class Elem>
void List<Elem>::push_front(const Elem& v)
{
first = new Link<Elem>(first, nullptr, v);
first->succ->prev = first; //link back
}
Your constructor for Link does not properly update the elements given as arguments. Inserting an element between two elements breaks the previous link.
This is a more appropriate constructor :
template <class Elem>
Link<Elem>::Link(Link<Elem>* s, const Elem& v)
: succ(s), prev(s->prev), val(v)
{
// Update next and previous nodes to make them aware of this
s->prev = this;
if(prev) prev->succ = this;
}
If you update List::push_front to use this constructor instead, you will find that your code compiles and runs.
You should consider making methods const when appropriate to avoid mistakes (or to spot existing onw them in the case of bool operator== (const Link<Elem>& src) const). Link.

Unexpected End of File error on .hpp File

I'm working on a file, Deque.hpp, which uses an iterator class and Nodes to make a deque, but I'm getting the error:
"Error C1004 unexpected end-of-file found "
I can't seem to find what's causing this. Here's my code.
#ifndef DEQUE_H
#define DEQUE_H
#include <iostream>
#include <new>
#include <cstdlib>
#include <algorithm>
//
//
//
template <typename T>
class Deque
{
public:
Deque();
Deque(const Deque & rhs);
~Deque();
Deque & operator= (const Deque & rhs);
Deque(Deque && rhs) : theSize{ rhs.theSize }, head{ rhs.head }, tail{ rhs.tail };
Deque & operator= (Deque && rhs);
T & Deque<T>::operator[](int n);
Iterator begin();
const_iterator begin() const;
Iterator end();
const_iterator end() const;
int size() const;
bool isEmpty() const;
void clear();
T & left();
const T & left() const;
T & right();
const T & right() const;
void pushLeft(const T & x);
void pushLeft(T && x);
void pushRight(const T & x);
void pushRight(T && x);
T & popLeft();
T & popRight();
bool Deque<T>::contains(const T&);
struct Node
{
T data;
Node *prev;
Node *next;
Node(const T & d = T{}, Node * p = NULL, Node * n = NULL) :
data{ d }, prev{ p }, next{ n } {}
Node(T && d, Node * p = NULL, Node * n = NULL)
: data{ std::move(d) }, prev{ p }, next{ n } {}
};
class const_iterator
{
public:
const_iterator() : current{ NULL } { }
const T & operator* () const;
const_iterator & operator++ ();
const_iterator & operator-- (); //!
const_iterator operator++ (int);
const_iterator operator-- (int); //!
bool operator== (const const_iterator & rhs) const;
bool operator!= (const const_iterator & rhs) const;
protected:
Node *current;
T & retrieve() const;
const_iterator(Node *p) : current{ p } { }
friend class Deque<T>;
};
class Iterator : public const_iterator
{
public:
Iterator();
T & operator* ();
const T & operator* () const;
Iterator & operator++ ();
Iterator & operator-- (); //!
Iterator operator++ (int);
Iterator operator-- (int); //!
protected:
Iterator(Node *p) : const_iterator{ p } { }
friend class Deque<T>;
};
private:
// Insert x before itr.
Iterator insert(Iterator itr, const T & x);
// Insert x before itr.
Iterator insert(Iterator itr, T && x);
// Erase item at itr.
Iterator erase(Iterator itr);
Iterator erase(Iterator from, Iterator to);
int theSize;
Node *head;
Node *tail;
void init();
};
template<typename T>
inline const T & Deque<T>::const_iterator::operator*() const
{
return retrieve();
}
template<typename T>
inline const_iterator & Deque<T>::const_iterator::operator++()
{
current = current->next;
return *this;
}
template<typename T>
inline const_iterator & Deque<T>::const_iterator::operator--()
{
current = current->prev;
return *this;
}
template<typename T>
inline const_iterator Deque<T>::const_iterator::operator++(int)
{
const_iterator old = *this;
++(*this);
return old;
}
template<typename T>
inline const_iterator Deque<T>::const_iterator::operator--(int)
{
const_iterator old = *this;
--(*this);
return old;
}
template<typename T>
inline bool Deque<T>::const_iterator::operator==(const const_iterator & rhs) const
{
return current == rhs.current;
}
template<typename T>
inline bool Deque<T>::const_iterator::operator!=(const const_iterator & rhs) const
{
return !(*this == rhs);
}
template<typename T>
inline T & Deque<T>::const_iterator::retrieve() const
{
return current->data;
}
template<typename T>
inline Deque<T>::Iterator::Iterator()
{
}
template<typename T>
inline T & Deque<T>::Iterator::operator*()
{
return const_iterator::retrieve();
}
template<typename T>
inline const T & Deque<T>::Iterator::operator*() const
{
return const_iterator::operator*();
}
template<typename T>
inline Iterator & Deque<T>::Iterator::operator++()
{
this->current = this->current->next;
return *this;
}
template<typename T>
inline Iterator & Deque<T>::Iterator::operator--()
{
this->current = this->current->prev;
return *this;
}
template<typename T>
inline Iterator Deque<T>::Iterator::operator++(int)
{
Iterator old = *this;
++(*this);
return old;
}
template<typename T>
inline Iterator Deque<T>::Iterator::operator--(int)
{
Iterator old = *this;
--(*this);
return old;
}
template<typename T>
inline Deque<T>::Deque()
{
init();
}
template<typename T>
inline Deque<T>::~Deque()
{
clear();
delete head;
delete tail;
}
template<typename T>
inline Deque & Deque<T>::operator=(const Deque & rhs)
{
if (this == &rhs)
return *this;
clear();
for (const_iterator itr = rhs.begin(); itr != rhs.end(); ++itr)
pushRight(*itr)
return *this;
}
template<typename T>
inline Deque<T>::Deque(Deque && rhs)
{
rhs.theSize = 0;
rhs.head = NULL;
rhs.tail = NULL;
}
template<typename T>
inline Deque & Deque<T>::operator=(Deque && rhs)
{
std::swap(theSize, rhs.theSize);
std::swap(head, rhs.head);
std::swap(tail, rhs.tail);
return *this;
}
template<typename T>
inline T & Deque<T>::operator[](int n)
{
Iterator itr = begin();
for (int i = 0; i < n; i++)
{
itr.current = itr.current->next;
}
return itr.current->data;
}
template<typename T>
inline Iterator Deque<T>::begin()
{
return{ head->next };
}
template<typename T>
inline const_iterator Deque<T>::begin() const
{
return{ head->next };
}
template<typename T>
inline Iterator Deque<T>::end()
{
return{ tail->prev }; //changed to -> prev
}
template<typename T>
inline const_iterator Deque<T>::end() const
{
return{ tail->prev };
}
template<typename T>
inline int Deque<T>::size() const
{
return theSize;
}
template<typename T>
inline bool Deque<T>::isEmpty() const
{
return size() == 0;
}
template<typename T>
inline void Deque<T>::clear()
{
while (!isEmpty())
popLeft();
}
template<typename T>
inline T & Deque<T>::left()
{
return *begin();
}
template<typename T>
inline const T & Deque<T>::left() const
{
return *begin();
}
template<typename T>
inline T & Deque<T>::right()
{
return *end(); // deleted "--*end"
}
template<typename T>
inline const T & Deque<T>::right() const
{
return *end();
}
template<typename T>
inline void Deque<T>::pushLeft(const T & x)
{
insert(begin(), x);
}
template<typename T>
inline void Deque<T>::pushLeft(T && x)
{
insert(begin(), std::move(x)); // changed std::move(x)) to x
}
template<typename T>
inline void Deque<T>::pushRight(const T & x)
{
insert(end(), x);
}
template<typename T>
inline void Deque<T>::pushRight(T && x)
{
insert(end(), std::move(x));
}
template<typename T>
inline T & Deque<T>::popLeft()
{
return *begin(); erase(begin());
}
template<typename T>
inline T & Deque<T>::popRight()
{
return *end(); erase(end()); // changed --end to end
}
template<typename T>
inline bool Deque<T>::contains(const T &)
{
// stuff here
}
template<typename T>
inline Iterator Deque<T>::insert(Iterator itr, const T & x)
{
Node *p = itr.current;
theSize++;
return{ p->prev = p->prev->next = new Node{ x, p->prev, p } };
}
template<typename T>
inline Iterator Deque<T>::insert(Iterator itr, T && x)
{
Node *p = itr.current;
theSize++;
return{ p->prev = p->prev->next = new Node{ std::move(x), p->prev, p } };
}
template<typename T>
inline Iterator Deque<T>::erase(Iterator itr)
{
Node *p = itr.current;
Iterator retVal{ p->next };
p->prev->next = p->next;
p->next->prev = p->prev;
delete p;
theSize--;
return retVal;
}
template<typename T>
inline Iterator Deque<T>::erase(Iterator from, Iterator to)
{
for (Iterator itr = from; itr != to; )
itr = erase(itr);
return to;
}
template<typename T>
inline void Deque<T>::init()
{
theSize = 0;
head = new Node;
tail = new Node;
head->next = tail;
tail->prev = head;
}
template<typename T>
inline Deque<T>::Deque(const Deque & rhs)
{
init();
*this = rhs;
}
#endif
The first error to fix is the one identified by Algirdas Preidžius: your constructor has an initialization list but no body.
You should replace
Deque(Deque && rhs) : theSize{ rhs.theSize }, head{ rhs.head }, tail{ rhs.tail };
by
Deque(Deque && rhs) : theSize{ rhs.theSize }, head{ rhs.head }, tail{ rhs.tail } {};
Then you'll have a lot of other errors to fix. Good luck !
My advice when coding: write your code incrementaly, build and test regularly. You shouldn't have so much errors to fix at once !
By the way, any reason to not use std::deque ?

Template Class in C++ - trouble writing begin for linked list

I'm a very confused student. Any help you can give is appreciated. I'm unsure how to write this code for a template class. I keep getting some odd compiling errors that look like this:
g++ -c test_list.cpp
List.cpp: In constructor ‘cop4530::List<T>::iterator::iterator(cop4530::List<T>::Node*) [with T = int]’:
List.cpp:247: instantiated from ‘typename cop4530::List<T>::iterator cop4530::List<T>::begin() [with T = int]’
test_list.cpp:25: instantiated from here
List.cpp:112: error: invalid conversion from ‘cop4530::List<int>::Node*’ to ‘int’
List.cpp:112: error: initializing argument 1 of ‘cop4530::List<T>::Node::Node(const T&, cop4530::List<T>::Node*, cop4530::List<T>::Node*) [with T = int]’
List.cpp: In constructor ‘cop4530::List<T>::iterator::iterator(cop4530::List<T>::Node*) [with T = std::basic_string<char, std::char_traits<char>, std::allocator<char> >]’:
List.cpp:247: instantiated from ‘typename cop4530::List<T>::iterator cop4530::List<T>::begin() [with T = std::basic_string<char, std::char_traits<char>, std::allocator<char> >]’
test_list.cpp:134: instantiated from here
List.cpp:112: error: no match for ‘operator=’ in ‘*((cop4530::List<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::iterator*)this)->cop4530::List<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::iterator::<anonymous>.cop4530::List<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::const_iterator::current = p’
List.h:11: note: candidates are: cop4530::List<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::Node& cop4530::List<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::Node::operator=(const cop4530::List<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::Node&)
make: *** [test_list.o] Error 1
Most importantly - Here is the exact code I am trying to fix:
template <class T>
typename List<T>::iterator List<T>::begin()
{ // iterator to first element
if (!empty())
return iterator( head->next );
}
Here is the full header:
#ifndef DL_LIST_H
#define DL_LIST_H
#include <iostream>
namespace cop4530 {
template <typename T>
class List {
private:
// nested Node class
struct Node {
T data;
Node *prev;
Node *next;
Node(const T & d = T(), Node *p = NULL, Node *n = NULL)
: data(d), prev(p), next(n) {}
};
public:
//nested const_iterator class
class const_iterator {
public:
const_iterator(); // default zero parameter constructor
const T & operator*() const; // operator*() to return element
// increment/decrement operators
const_iterator & operator++();
const_iterator operator++(int);
const_iterator & operator--();
const_iterator operator--(int);
// comparison operators
bool operator==(const const_iterator &rhs) const;
bool operator!=(const const_iterator &rhs) const;
protected:
Node *current; // pointer to node in List
T & retrieve() const; // retrieve the element refers to
const_iterator(Node *p); // protected constructor
friend class List<T>;
};
// nested iterator class
class iterator : public const_iterator {
public:
iterator() {}
T & operator*();
const T & operator*() const;
// increment/decrement operators
iterator & operator++();
iterator operator++(int);
iterator & operator--();
iterator operator--(int);
protected:
iterator(Node *p);
friend class List<T>;
};
public:
// constructor, desctructor, copy constructor
List(); // default zero parameter constructor
List(const List &rhs); // copy constructor
// num elements with value of val
explicit List(int num, const T& val = T());
// constructs with elements [start, end)
List(const_iterator start, const_iterator end);
~List(); // destructor
// assignment operator
const List& operator=(const List &rhs);
// member functions
int size() const; // number of elements
bool empty() const; // check if list is empty
void clear(); // delete all elements
void reverse(); // reverse the order of the elements
T &front(); // reference to the first element
const T& front() const;
T &back(); // reference to the last element
const T & back() const;
void push_front(const T & val); // insert to the beginning
void push_back(const T & val); // insert to the end
void pop_front(); // delete first element
void pop_back(); // delete last element
void remove(const T &val); // remove all elements with value = val
// print out all elements. ofc is deliminitor
void print(std::ostream& os, char ofc = ' ') const;
iterator begin(); // iterator to first element
const_iterator begin() const;
iterator end(); // end marker iterator
const_iterator end() const;
iterator insert(iterator itr, const T& val); // insert val ahead of itr
iterator erase(iterator itr); // erase one element
iterator erase(iterator start, iterator end); // erase [start, end)
private:
int theSize; // number of elements
Node *head; // head node
Node *tail; // tail node
void init(); // initialization
};
// overloading comparison operators
template <typename T>
bool operator==(const List<T> & lhs, const List<T> &rhs);
template <typename T>
bool operator!=(const List<T> & lhs, const List<T> &rhs);
// overloading output operator
template <typename T>
std::ostream & operator<<(std::ostream &os, const List<T> &l);
// include the implementation file here
#include "List.cpp"
} // end of namespace 4530
#endif
Here is most of the .cpp:
using namespace std;
// --------------------- CONST_ITERATOR --------------------- //
template <class T>
List<T>::const_iterator::const_iterator()
{ // default zero-parameter constructor. Set pointer current to NULL.
current = NULL;
}
template <class T>
const T& List<T>::const_iterator::operator*() const
{ // returns a reference to the corresponding element in the list by calling retrieve() member function.
return retrieve();
}
template <class T>
typename List<T>::const_iterator& List<T>::const_iterator::operator++()
{
current = current->next;
return *this;
}
template <class T>
typename List<T>::const_iterator List<T>::const_iterator::operator++(int)
{
const_iterator old = *this;
++( *this );
return old;
}
template <class T>
typename List<T>::const_iterator& List<T>::const_iterator::operator--()
{
current = current->prev;
return *this;
}
template <class T>
typename List<T>::const_iterator List<T>::const_iterator::operator--(int)
{
const_iterator old = *this;
--( *this );
return old;
}
template <class T>
bool List<T>::const_iterator::operator==(const const_iterator &rhs) const
{return current == rhs.current;}
template <class T>
bool List<T>::const_iterator::operator!=(const const_iterator &rhs) const
{return !( *this == rhs );}
template <class T>
T& List<T>::const_iterator::retrieve() const
{ // return a reference to the corresponding element in the list.
return current->data;
}
template <class T>
List<T>::const_iterator::const_iterator(Node *p)
{ // one-parameter constructor
// Set pointer current to the given node pointer p.
current = p;
}
// --------------------- ITERATOR --------------------- //
template <typename T>
T& List<T>::iterator::operator*()
{
return List<T>::iterator::retrieve();
}
template <typename T>
const T& List<T>::iterator::operator*() const
{
return List<T>::iterator::retrieve();
}
template <class T>
typename List<T>::iterator& List<T>::iterator::operator++()
{
*this->current = *this->current->next;
return *this;
}
template <class T>
typename List<T>::iterator List<T>::iterator::operator++(int)
{
iterator old = *this;
++( *this );
return old;
}
template <class T>
typename List<T>::iterator& List<T>::iterator::operator--()
{
*this->current = *this->current->prev;
return *this;
}
template <class T>
typename List<T>::iterator List<T>::iterator::operator--(int)
{
iterator old = *this;
--( *this );
return old;
}
template <class T>
List<T>::iterator::iterator(Node *p)
{ // one-parameter constructor
// Set current to the given node pointer p
*this->current = p;
}
// --------------------- LIST --------------------- //
template <class T>
List<T>::List()
{ init(); }
template <class T>
List<T>::List( const List & rhs )
{ // Copy constructor
init();
*this = rhs;
}
template <class T>
List<T>::List(int num, const T& val)
{ //Constructs a list with num elements, all initialized with value val
init();
iterator itr = begin();
for (int i = 0; i < num; ++i)
{
insert(itr, val);
++itr;
}
}
template <class T>
List<T>::~List()
{ // Destructor
clear();
delete head;
delete tail;
}
template <class T>
const typename List<T>::List& List<T>::operator=(const List &rhs)
{ // Assignment operator
iterator ritr = rhs.first();
iterator itr = begin();
if( this != &rhs )
{
clear();
for( ; ritr != NULL; ritr++, itr++ )
insert( ritr.retrieve( ), itr );
}
return *this;
}
template <class T>
int List<T>::size() const
{ // return the number of elements in the List
return theSize;
}
template <class T>
bool List<T>::empty() const
{ // check if list is empty
return head->next == NULL;
}
template <class T>
void List<T>::clear()
{ // delete all elements
while( !empty() )
erase( begin() );
}
template <class T>
T& List<T>::front()
{ // reference to the first element
return head->next->data;
}
template <class T>
typename List<T>::iterator List<T>::begin()
{ // iterator to first element
if (!empty())
return iterator( head->next );
}
template <class T>
typename List<T>::iterator List<T>::end()
{ // end marker iterator
if (!empty())
return iterator( tail->prev );
}
template <class T>
typename List<T>::iterator List<T>::insert( iterator itr, const T & x )
{
Node *p = itr.current;
theSize++;
return iterator( p->prev = p->prev->next = new Node( x, p->prev, p) );
}
template <class T>
typename List<T>::iterator List<T>::erase( iterator itr )
{
Node *p = itr.current;
iterator retVal( p->next );
p->prev->next = p->next;
p->next->prev = p->prev;
delete p;
theSize--;
return retVal;
}
template <class T>
typename List<T>::iterator List<T>::erase( iterator start, iterator end )
{
for( iterator itr = start; itr != end; )
itr = erase( itr );
return end;
}
template <class T>
void List<T>::init()
{ // Initaialize the member variables of a List
theSize = 0;
head = new Node;
tail = new Node;
head->next = tail;
tail->prev = head;
}
Let me first tell you (a) I know they are in separate files which is a big no-no for class templates, but I cannot change it for this assignment. (b) This is for homework. (c) I've tried a few variations of this code that fetches either more or less compile errors along the same vein. If you help me I will be so happy... Been at this for an hour or two.
Thanks! If you need any more info, let me know!
This is your problem:
return iterator itr( head->next );
You should probably be doing this:
return iterator( head->next );
The code as you have it is trying to declare an iterator named itr, which is a statement, not an expression (as required by return).
I'm not using the same compiler as you, but; I included the header in the cpp rather than the other way around, added a 'using' for your namespace in the cpp, and fixed the function signature of the implementation of operator= and that got what you've given us to build.

c++ sort function of List

My sort function looks like this:
template <typename Compare, typename T>
void List<T>::sort(const Compare& comparer){
...
}
But I received next error:
template definition of non-template
void List<T>::sort(const Compare&)'
invalid use of undefined typeclass
List'
What does it mean?
This is the complete code of the list:
template <typename T> class Node;
template <typename T> class Iterator;
template <typename T>
class List{
private:
Node<T> * first;
Node<T> * last;
int size;
friend class Predicate ;
friend class Compare;
public:
typedef Iterator<T> iterator;
List(){
first = NULL;
last = NULL;
size = 0;
}
List(const List<T> & l);
void pushBack(T element);
void insert( const T& element, iterator i);
iterator remove(iterator i);
iterator find(const Predicate& predicate);
void sort(const Compare& comparer);
int getSize() const;
iterator begin();
iterator end();
~List();
};
template <class T>
List<T>::List(const List & l) {
first = 0;
last = 0;
size = 0;
for (Node<T> * current = l.first; current != 0; current = current -> next){
pushBack(current -> data);
}
}
template <typename T>
void List<T>::pushBack(T element){
Node<T>* newnode = new Node<T>(element);
if (newnode->prev == NULL) {
first = newnode;
last = newnode;
}else{
newnode->prev = last;
last->next = newnode;
last = newnode;
}
}
template <typename T>
void List<T>::insert( const T& element, iterator i){
if (i.position == NULL){
pushBack(element);
++size;
return;
}
Node<T>* after = i.position;
Node<T>* before = after->prev;
Node<T>* newnode = new Node<T>(element);
newnode->prev = before;
newnode->next = after;
after->prev = newnode;
if (before == NULL) {
first = newnode;
}
else{
before->next = newnode;
}
++size;
}
template <typename T>
typename List<T>::iterator List<T>::remove(iterator iter){
if(iter.position != NULL){
Node<T>* remove = iter.position;
Node<T>* before = remove->prev;
Node<T>* after = remove->next;
if (remove == first){
first = after;
} else{
before->next = after;
}
if (remove == last){
last = before;
}else{
after->prev = before;
}
iter.position = after;
--size;
delete remove;
return iter;
}else{
throw ElementNotFound();
}
}
template <typename T>
typename List<T>::iterator List<T>::begin(){
//iterator iter;
//iter.position = first;
//iter.last = last;
return iterator(first);
}
template <typename T>
typename List<T>::iterator List<T>::end(){
return iterator (last);
}
template <typename Predicate, typename T>
List<T>::iterator List<T>::find(const Predicate& predicate){
iterator iter;
for( iter = begin(); iter != end(); iter = next()){
if( predicate(iter.getElement())){
return iter;
}
}
return end();
}
template <typename Compare, typename T>
void List<T>::sort(const Compare& comparer){
Iterator<T> iter;
for( iter = begin(); iter != end(); iter = iter.next() ){
if( comparer( iter.getElement() , (iter+1).getElement()) != true){
}
}
}
template <typename T>
int List<T>::getSize() const{
return size;
}
template <class T>
List <T>::~List() {
Node <T> * firstNode = first;
while (firstNode != 0) {
Node <T> * nextNode = firstNode->next;
delete firstNode;
firstNode = nextNode;
}
}
template <typename T> class Node {
private:
T data;
Node* next;
Node* prev;
friend class List<T>;
friend class Iterator<T>;
public:
Node(T element){
data = element;
prev = NULL;
next = NULL;
}
~Node(){}
};
template <typename T> class Iterator{
private:
Node<T>* position;
Node<T>* last;
friend class List<T>;
public:
Iterator(){
position = NULL;
last = NULL;
}
Iterator(Node<T> * source): position(source) { }
T& getElement()const;
bool operator==(Iterator b) const;
bool operator!=(Iterator b) const;
T & operator*();
Iterator & operator++();
Iterator & operator++(int);
~Iterator(){}
};
template <class T>
T& Iterator<T>::getElement() const{
if(position != NULL){
return position->data;
}
else{
throw ElementNotFound();
}
}
template <typename T>
bool Iterator<T>::operator==(Iterator b) const{
return position == b.position;
}
template <typename T>
bool Iterator<T>::operator!=(Iterator b) const{
return position != b.position;
}
template <typename T>
T & Iterator<T>::operator*() {
return position->data;
}
template <class T>
Iterator<T> & Iterator<T>::operator++() {
position = position->next;
return *this;
}
template <class T>
Iterator<T> & Iterator<T>::operator++(int){
position = position->next;
return *this;
}
#endif /* LISTGENERIC_H_ */
Either you declare sort as a template function with one template argument (Compare) inside the class. Then your definition has to look as follows:
template <typename T>
template <typename Compare>
void List<T>::sort(const Compare& comparer) {
…
}
And you also need to remove the now redundant friend class Compare declaration from your List class.
Or you keep Compare and sort as-is. In this case, simply don’t have sort as a template, and omit the Compare template argument:
template <typename T>
void List<T>::sort(const Compare& comparer) {
…
}
Of course this only works if you have defined (not just declared!) the class Compare before this function.
But this second solution would be highly unorthodox and pretty useless since the compare argument doesn’t make much sense: there is only one Compare class and the user cannot change it. Normally, this should be a template argument (first solution).