Assignments | Course Home | Documentation | Lab Hours/Tutoring | Schedule | Submit

Saint Louis University

Computer Science 2100
Data Structures

Michael Goldwasser

Fall 2015

Dept. of Math & Computer Science

Programming Assignment 03
Smart Stacks

Due: Monday, 12 October 2015, 11:59pm

Please see the general programming webpage for details about the programming environment for this course, guidelines for programming style, and details on electronic submission of assignments.

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 head = head->next and decrement n 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. (Think about what happens when stacks are empty, or when we start sharing nodes among three or more stacks.). Feel free to modify the test code for your own testing purposes.

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.


Files to Submit


Grading Standards

The assignment is worth 20 points.


Extra Credit

Earlier, we discussed the danger with the non-const version of top, as an assignment to that reference from the context of one stack might violate the state of an "independent" stack that is sharing that node.

Update your SmartStack class by properly implementing a non-const version of top. Of course, you will need to modify the test program to exercise your new behavior.


Michael Goldwasser
CSCI 2100, Fall 2015
Last modified: Monday, 19 October 2015
Assignments | Course Home | Documentation | Lab Hours/Tutoring | Schedule | Submit