Since my original Stack
implementation has lots of bugs that I did not notice, I thought I would recreate and try to improve it. Please review this version.
Note about pointers: I know using std::unique_ptr
is better so we don't need to do manual deletes, but when I tried it here it results in disaster. I think I don't yet know how to really use it. So I did not use it in this code.
template<class T>
struct Node {
T item;
Node* next;
Node(const T& t, Node* link) :item{t}, next{link} { }
};
template<class T>
class Stack {
public:
Stack() : first{nullptr}, n{0} {}
int size() const { return n; }
bool empty() const { return n == 0; }
Stack(const Stack&);
Stack(Stack&&);
Stack& operator=(const Stack&);
Stack& operator=(Stack&&);
void push(const T&);
void pop();
T peek() const;
~Stack() {
while (!empty()) {
pop();
}
}
private:
Node<T>* first;
std::size_t 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=(const Stack& s) {
for (auto t = s.first; t != nullptr; t = t->next) {
push(t->item);
}
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) {
first = s.first;
n = s.n;
s.first = nullptr;
s.n = 0;
return *this;
}
template<class T>
void Stack<T>::push(const T& t) {
first = new Node<T>{t,first};
++n;
}
template<class T>
void Stack<T>::pop() {
if (empty()) {
throw std::out_of_range("underflow");
}
Node<T>* oldfirst = first;
first = first->next;
delete oldfirst;
--n;
}
template<class T>
T Stack<T>::peek() const {
if (empty()) {
throw std::out_of_range("underflow");
}
return first->item;
}
How can I make this code better, particularly copy and move?