This is a followup to
Please review my hopefully improved stack implementation
- As suggested by some answers to my previous code, some of the functions can be overloaded to provide versions of return by value, return by reference and const or pass by value, pass by reference and const, but the function definitions are almost the same so I did not add it here.
- Regarding pointers, I know std::unique_ptr will be better and I already saw an implementation through an answer to my previous code, but I like to play with normal pointers right now.
template<class T>
class Stack {
using stacksize = std::size_t;
public:
Stack() : first{nullptr}, n{0} {}
stacksize size() const { return n; }
bool empty() const { return n == 0; }
Stack(const Stack&);
Stack(Stack&&);
Stack& operator=(Stack);
Stack& operator=(Stack&&);
T& operator[](const stacksize& i) {
Node* traverse = first;
stacksize x = 0;
while (x < i) {
traverse = traverse->next;
++x;
}
return traverse->item;
}
void push(const T&);
void pop();
T& peek() const;
~Stack() {
while (!empty()) {
pop();
}
}
private:
struct Node {
T item;
Node* next;
Node(const T& t, Node* link) :item{t}, next{link} { }
};
Node* first;
stacksize n;
};
template<class T>
Stack<T>::Stack(const Stack& s) :first{nullptr}, n{0}{
for (auto t = s.first; t != nullptr; t = t->next) {
push(t->item);
}
}
template<class T>
Stack<T>& Stack<T>::operator=(Stack s) {
std::swap(first,s.first);
std::swap(n,s.n);
return *this;
}
template<class T>
Stack<T>::Stack(Stack&& s) :first{s.first}, n{s.n} {
s.first = nullptr;
s.n = 0;
}
template<class T>
Stack<T>& Stack<T>::operator=(Stack&& s) {
std::swap(s.n,n);
std::swap(s.first,first);
return *this;
}
template<class T>
void Stack<T>::push(const T& t) {
first = new Node{t,first};
++n;
}
template<class T>
void Stack<T>::pop() {
Node* oldfirst = first;
first = first->next;
delete oldfirst;
--n;
}
template<class T>
T& Stack<T>::peek() const {
return first->item;
}