I've implemented a simple C++ STL like queue. (I've tried to follow @LokiAstari stack implementation code fashion)
#ifndef QUEUE_H
#define QUEUE_H
#include <iostream>
#include <stdexcept>
using std::cout;
template <typename T>
class queue {
public:
struct node {
T data;
node *next;
node()
: data(0)
, next(nullptr) {
}
node(T const& data, node* next)
: data(data)
, next(next) {
}
node(T&& data, node* next)
: data(std::move(data))
, next(next) {
}
};
~queue();
bool empty() const;
size_t size() const;
T front() const;
void push(T const& data);
void push(T&& data);
//void emplace (T&&... args);
// void swap (queue& x);
void pop();
private:
size_t elements = 0;
node *head = nullptr;
node *tail = nullptr;
};
template <typename T>
queue<T>::~queue() {
node *curr = new node();
while(head) {
curr = head;
head = head->next;
delete curr;
}
delete tail;
}
template <typename T>
bool queue<T>::empty() const {
return elements == 0;
// return head == nullptr;
}
template <typename T>
size_t queue<T>::size() const {
return elements;
}
template <typename T>
T queue<T>::front() const {
if(elements == 0)
throw std::runtime_error("Invalid Action");
return head->data;
}
template <typename T>
void queue<T>::push(T const& data) {
node *newNode = new node(data, nullptr);
if(!elements) head = newNode;
else tail->next = newNode;
tail = newNode;
++elements;
}
template <typename T>
void queue<T>::push(T&& data) {
node *newNode = new node(std::move(data), nullptr);
if(!elements) head = newNode;
else tail->next = newNode;
tail = newNode;
++elements;
}
template <typename T>
void queue<T>::pop() {
if(elements == 0)
throw std::runtime_error("Invalid Action");
node *tmp = new node();
if(elements != 0) tmp = head;
head = head->next;
--elements;
delete tmp;
}
#endif // QUEUE_H
I would appreciate all criticism relevant to code, style, flow, camelCase vs underscore, and so forth.
Also can you give me some insight on how I can implement the C++11 features like emplace(T&& data)
and swap(queue& x)
efficiently?
Edit (After applying most of the suggestions)
#ifndef QUEUE_H
#define QUEUE_H
#include <iostream>
#include <stdexcept>
template <typename T>
class queue {
public:
~queue();
bool empty() const;
size_t size() const;
T const& front() const;
T& front();
void push(T const& data);
void push(T&& data);
//void emplace (T&&... args);
// void swap (queue& x);
void pop();
private:
size_t elements = 0;
struct node {
T data;
node *next;
node(T const& data, node* next)
: data(data)
, next(next) {
}
node(T&& data, node* next)
: data(std::move(data))
, next(next) {
}
};
node *head = nullptr;
node *tail = nullptr;
};
template <typename T>
queue<T>::~queue() {
node *curr;
while(head) {
curr = head;
head = head->next;
delete curr;
}
}
template <typename T>
bool queue<T>::empty() const {
return elements == 0;
// return head == nullptr;
}
template <typename T>
size_t queue<T>::size() const {
return elements;
}
template <typename T>
T const& queue<T>::front() const {
if(head == nullptr)
throw std::runtime_error("Invalid Action");
return head->data;
}
template <typename T>
T& queue<T>::front() {
if(head == nullptr)
throw std::runtime_error("Invalid Action");
return head->data;
}
template <typename T>
void queue<T>::push(T const& data) {
node *newNode = new node(data, nullptr);
if(head == nullptr) head = newNode;
else tail->next = newNode;
tail = newNode;
++elements;
}
template <typename T>
void queue<T>::push(T&& data) {
node *newNode = new node(std::move(data), nullptr);
if(head == nullptr) head = newNode;
else tail->next = newNode;
tail = newNode;
++elements;
}
template <typename T>
void queue<T>::pop() {
if(head == nullptr)
throw std::runtime_error("Invalid Action");
node* remove = head;
head = head->next;
delete remove;
--elements;
}
#endif // QUEUE_H