I feel like there is room for improvement in the push/pop methods. Any suggestions?
#include <exception>
template <typename T>
class List
{
public:
List();
~List();
void PushBack(const T &data);
void PushFront(const T &data);
void PopBack();
void PopFront();
void Clear();
bool IsEmpty() const;
unsigned int Size() const;
T& Front() const;
T& Back() const;
private:
template <typename T>
struct Node
{
Node(const T &data) : data(data), next(NULL) {}
T data;
Node *next;
};
Node<T> *head;
Node<T> *tail;
};
template <typename T>
List<T>::List()
: head(NULL),
tail(NULL)
{
}
template <typename T>
List<T>::~List()
{
Clear();
}
template <typename T>
void List<T>::PushBack(const T &data)
{
if ( !head )
{
head = new Node<T>(data);
tail = head;
return;
}
tail->next = new Node<T>(data);
tail = tail->next;
}
template <typename T>
void List<T>::PushFront(const T &data)
{
Node<T> *tmp = head;
head = new Node<T>(data);
head->next = tmp;
if ( !tail )
{
tail = head;
}
}
template <typename T>
void List<T>::PopBack()
{
//empty list
if ( !head )
{
throw std::out_of_range("Can't pop from empty list");
}
//list with one element
if ( head == tail )
{
delete head;
head = NULL;
tail = NULL;
return;
}
Node<T> *current = head;
while ( current->next != tail )
{
current = current->next;
}
delete tail;
tail = current;
tail->next = NULL;
}
template <typename T>
void List<T>::PopFront()
{
//empty list
if ( !head )
{
throw std::out_of_range("Can't pop from empty list");
}
//list with one element
if ( head == tail )
{
delete head;
head = NULL;
tail = NULL;
return;
}
Node<T> *tmp = head->next;
delete head;
head = tmp;
}
template <typename T>
void List<T>::Clear()
{
Node<T> *current = head;
while ( head )
{
current = head;
head = head->next;
delete current;
}
head = NULL;
tail = NULL;
}
template <typename T>
bool List<T>::IsEmpty() const
{
return ( head == NULL );
}
template <typename T>
unsigned int List<T>::Size() const
{
unsigned int size = 0;
for ( Node<T> *current = head; current; current = current->next )
{
++size;
}
return size;
}
template <typename T>
T& List<T>::Front() const
{
if ( !head )
{
throw std::out_of_range("Can't return value from empty list");
}
return head->data;
}
template <typename T>
T& List<T>::Back() const
{
if ( !head )
{
throw std::out_of_range("Can't return value from empty list");
}
return tail->data;
}