Homework 4
Smart Stacks

Due: Saturday, Feb. 23, 11:59pm (via git)

The files you may need for this assignment can be downloaded here.

Collaboration Policy

For this assignment, you are allowed to work with one other student if you wish (in fact, we suggest that you do so). If any student wishes to have a partner but has not been able to locate one, please let the instructor know so that we can match up partners.

Please make sure you adhere to the policies on academic integrity in this regard.


Contents:


Overview

We have emphasized the importance of a class's "housekeeping" functions (the copy constructor, assignment operator, and destructor). At times we have differentiated between the default behaviors provided by C++ which perform what is known as a shallow copy, and our own implementation for providing what is known as a deep copy.

As an example, we gave a linked-list implementation of a stack in an earlier lecture. If we do not explicitly provide non-trivial housekeeping functions, the default copy constructor produces a shallow copy as portrayed in the following figure.

Such an image of a shallow copy should sound a warning for an experienced C++ programmer, as the two stacks do not seem to have independent state. Interestingly, in the case of a stack, things are not quite as bad as they seem. For example, if we make a call to s.push('E') using the original implementation, we get the following internal configuration.

Yet this is not necessarily a disaster. From the perspective of s we seem to have a linked list of five elements, and from the perspective of t we seem to have a linked list of four elements.

If we were to continue with a call to t.pop() from this point, we would set tp = tp->next and decrement sz leading to the following state.

We do not yet have a disaster on our hands. In fact, if we used the original LinkedStack class with the default housekeeping functions, there are only two potential flaws with the entangled states.


Maintaining Reference Counts

The challenge we face is that sometimes when popping an item or deallocating a stack we need to delete a node, yet other times we need to leave such a node in memory because it is still part of a list for another stack. Our solution is to explicitly maintain a reference count for each node in the system. The reference count for a node is the number of live pointers that reference that node. Whenever a pointer is assigned to that node, the node's reference count should be incremented. Whenever a pointer to the node is reassigned elsewhere or outright destroyed, we decrement the node's reference count. When a node's reference count reaches zero it can safely be deleted as it is unreachable.


Your Task

Your goal is to implement a stack class that creates shallow copies for the copy constructor and assignment operator, with the use of reference counting for deleting unused nodes. We will start you off with a working implementation of the stack class that creates deep copies.

For accounting purposes, the code we provide manages an additional variable SmartStack::total that counts the overall number of nodes in the system. Please do not confuse this variable with the above mentioned reference counting. The total variable is a single static variable, meaning that it is not part of an individual node's state but instead shared globally throughout the program. In order to keep an accurate count of the number of nodes, we execute total++ inside the Node class constructor and total-- within the Node class destructor. Although you are welcome to make changes to those routines, please do not alter our management of the total variable.


A Detailed Example


Debugging Your Program

We offer the above example to demonstrate many of the complexities that arise for smart stacks. However, succeeding on this one example does not guarantee that your code is valid for all scenarios. You are responsible for thoroughly testing your own program, and we will certainly be running many additional tests when grading.

Also, please note that the dump method we have provided is used to print the element values in the underlying linked list. We strongly recommend having you change that method to include output for the reference counts as well, to provide you a more detailed behind-the-scene glimpse at the state of your stacks.


Files We Are Providing

All such files can be downloaded here; they are also in the course git repo.


Files to Submit


Grading Standards

The assignment is worth 10 points. Points will be assigned for correctness of your code as well as commenting and clarity; please note that the readme (including a clear description of any remaining issues in your code) will also be graded.