/*
* Another variation on the linked stack, this time using the unique_ptr
* library class to manage memory allocation. We still don't need a
* destructor.
*/
#ifndef _lnkstack4_h_
#define _lnkstack4_h_
#include <utility>
#include <memory>
using std::unique_ptr;
template <typename T>
class Stack {
public:
Stack() {
m_size = 0;
}
// Push the argument item.
void push(const T &itm) {
// Create a new node, holding it in a unique ptr. (The
// make_unique method is from the 2014 standandard.)
m_head = std::make_unique<node>(itm, m_head);
++m_size;
}
// Pop the argument item, and return true, or return false if the
// the stack is empty.
bool pop(T &itm) {
if(!m_head) return false;
itm = m_head->data();
m_head = std::move(m_head->next());
--m_size;
return true;
}
// Convenience to pop and return the top object. Only works
// for types where T() is a valid expression.
T pop() {
T ret;
if(pop(ret)) return ret;
return T();
}
// Tell if empty.
bool empty() {
return m_head;
}
// Report the size
int size() {
return m_size;
}
private:
// Nodes for the linked list.
class node {
public:
// Constructor for a node. Saves the arguments.
node(const T &d, unique_ptr<node> &n = nullptr) {
m_data = d;
m_next = std::move(n);
// The move operation leaves n NULL, moving the
// pointer, and reponsibility for it, to m_next.
}
const T& data() { return m_data; }
unique_ptr<node> &next() { return m_next; }
private:
T m_data;
unique_ptr<node> m_next;
};
unique_ptr<node> m_head;
int m_size;
};
#endif
Yet another version of the linked stack, this one using unique_ptr.
The unique_ptr type provides a different type of memory management. It is
more limited, and more awkward to use, but more efficient. Each
pointer points to exactly one object, which is deleted when the
the pointer is destroyed. This makes working with the pointers
problematic, since you can never create two copies. But most of
that can be enforced at compile time, which eliminates the
overhead of counting.
All pointer declarations
have been replaced with declarations of unique_ptr, and
we make objects with create_unique. Some things to note:
- The pop method does not assign next to to the head, it uses
the std::move utility. This does what it says: it moves the pointer
value from next to head, leaving the next pointer null without making a
copy. This also destroys the old value of itm which causes
the old head node that it pointed to to be deleted.
- The node class constructor takes a pointer by reference, and the
next method returns by reference to avoid copying a shared_ptr value.
returns the next pointer by reference. It also uses move to
put the received pointer into the new node.
No destructor is needed for the same reason as in the last version.
The destruction of the object means the destruction of the head pointer,
which destroys the first node, and down the line.