Linked Stack Using Unique Pointer
/* * Another variation on the linked stack, this time using the unique_ptr * library class to manage memory allocation. We no longer need a * destructor, but using unique_ptr this way is clunky. */ #ifndef _lnkstack3_h_ #define _lnkstack3_h_ #include <utility> #include <memory> using std::unique_ptr; template <typename T> class Stack { public: // Why do we make a default constructor that doesn't do anything? // Apparently, deleting the copy constructor counts has having a // copy constructor, which counts as having at least one explicit // constructor, which eliminates the default default constructor, // which would have worked just fine. Say that three times fast. Stack() { } // Thou shalt not. Stack(const Stack<T>&) = delete; Stack & operator=(const Stack<T>&) = delete; // Push the argument item. void push(const T &itm) { // Create a new node, holding it in a unique ptr. m_head = unique_ptr<node>(new node(itm, m_head)); } // Pop the argument item, and return true, or return false if the // the stack is empty. bool pop(T &itm) { if(m_head == NULL) return false; itm = m_head->data(); m_head = std::move(m_head->next()); return true; } // Tell if empty. bool empty() { return m_head == NULL; } private: // Nodes for the linked list. class node { public: // Constructor for a node. Saves the arguments. node(const T &d, unique_ptr<node> &n = NULL) { 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; }; #endif

Yet another version of the linked stack, this one using unique_ptr. All pointer declarations have been replaced with declarations of unique_ptr Notice some differences to the previous version:

  1. The constructor is empty because m_head is now a smart pointer, and smart pointers initialize themselves to NULL.
  2. There is no destructor, since the smart pointer takes care of cleanup.
  3. When push creates a node, it wraps the new in the smart pointer constructor, which causes the unique_ptr object to take responsibility for deleting the object.
  4. The pop method is simplified because the node does not need to be explicitly deleted, but instead we have:
    m_head = std::move(m_head->next());
    The move method is used with unique_ptr to move the pointer (and the responsibility for deleting the object it points to) instead of copying it like a regular assignment. This actually leaves m_head->next() NULL. Then the change to m_head causes the node it used to point to to be automatically deleted, the same thing we had to take care of ourselves in the previous version.
  5. The node class constructor takes a pointer by reference, and returns the next pointer by reference. This is because unique_ptr objects do not care to be copied. The constructor takes in its argument pointer with this statement:
    m_next = std::move(n);
    Similar to the one above, it transfers the pointer (and ownership of the object pointed to) from the argument to the m_next pointer in the created node.
The automatic cleanup happens like this: when the Stack object is destroyed, all its parts are destroyed, including the m_head. When that is destroyed, it deletes the node it points to (top of the stack). When that first node is destroyed, its parts are destroyed, including m_next, which deletes what it points to, and so forth, until the whole list is destroyed. This is essentially a recursive walk of the list which occurs automatically when the stack object is destroyed.