CS 115: Assignment 5
Assignment 5
Due March 31, 2021
Overview
In this assignment, you will restructure your program to use dynamically allocated memory for the tiles.
The Board and AvailableTiles classes will be put in canonical form and the constructors,
destructors, and assignment operators will be written to allocate and deallocate the memory as needed.
Internally, the game board will be a statically allocated 2D a
ay of pointers (which will be set to point to
dynamically allocated tiles) and the list of available tiles will be represented as a linked list. Each linked
list element will store the tile cost and a pointer to a dynamically-allocated tile.
Note that the dynamically allocated tiles are always “owned” by the class that creates and deletes them.
When a tile is needed elsewhere, it is passed by reference and, if necessary, the client creates a copy for
its own use. No tile is ever created by one class and destroyed by another one. This reduces the chance
of memory e
ors, such as memory leaks (caused by forgetting to call delete) and dangling pointers
(caused by trying to use something after it was deleted).
The purpose of this assignment is to give you practice with dynamically allocated memory, including
linked lists, and with how classes can be used to avoid memory leaks. For Part A, you will change your
Board class to use dynamically allocated tiles. For Part B, you will create an encapsulated type to store
a linked list element. For Part C, you will refactor your AvailableTiles class to store the tiles and
costs in a linked list.
Dynamic Memory Management
Each piece of dynamically allocated memory in the program will be managed by a single class. That
class will be the only part of the program that ever has access to the pointer to that memory. It will
allocate and deallocate the dynamic memory. The constructors, destructor, and assignment operator
will be used to ensure that the memory is always allocated before it is used and deallocated when it is
no longer needed. Class invariants will be used to check that everything is working co
ectly.
The Board Class
The Board class will manage the Tiles by using a 2D a
ay of pointers; each pointer in the a
ay is a
pointer to a Tile (see diagram). None of these pointers will ever be nullptr. Suppose your a
ay is
named pb. Then:
pb[i][j] XXXXXXXXXXis one of the pointers that points to a Tile
*(pb[i][j] XXXXXXXXXXis the Tile being pointed to by pb[i][j]
pb[i][j] -> genus XXXXXXXXXXis the genus field of the Tile being pointed to by pb[i][j]
The AvailableTilesElement Class
The AvailableTilesElement class will manage a single Tile, which will never be nullptr. The
AvailableTilesElement class will also contain a next pointer that it will not manage. The data
structure for an AvailableTilesElement is as follows:
The AvailableTiles Class
The AvailableTiles class will manage a linked list of AvailableTilesElements, which will
contain 5 elements at the end of each public member function (except the destructor). As a result,
the head pointer will never be nullptr. As part of managing the linked list, the AvailableTiles
new Tile new Tile
new Tile new Tile
new Tile
new Tile
new Tile
new Tile
new Tile
new Tile
new Tile
new Tile
new Tile
new Tile
Board
Tile
owner genus species
int int int
AvailableTilesElement
ptile cost pnext
int
Memory managed by
AvailableTilesElement
class will manage the next pointers for the elements. The data structure for an AvailableTiles is
as follows:
Allocation Counting
Even when ADTs are used, linked lists are a common cause of memory leaks. In this assignment, we will
use a technique named allocation counting to detect (and then fix) memory leaks in the linked list. In
short, we will create a global variable refe
ed to here as the allocation counter and start it at zero.
Whenever we allocate a linked list element, we will increment the allocation counter. Whenever we
deallocate an element, we will decrement allocation counter. To ensure that we do not miss any
allocations, we will update the allocation counter in the constructors and destructor.
Ideally, we would like to print the value of the allocation counter once at the end of the program. If it
were positive, a memory leak would exist and if it were zero, one would not. (If it is ever negative, there
is a bug in the counting code.) However, making something happen "only at the end of the program" is
difficult. Instead, we will print the allocation counter whenever it is decreased to zero. Then we will see
if it is printed when the program ends.
If you want to find out more about when the linked list elements were allocated and deallocated, you
can print the allocation counter every time it is changed. However, this will produce a lot of extra
messages, so you should disable or remove such printing before turning in your assignment.
Requirements
Start by creating a new project (or new folder, etc.) for Assignment 5. Do not just modify Assignment 4.
If you are using Visual Studio, create a new project and copy in the code files (.h and .cpp) from
Assignment 4. Do not ever copy a Visual Studio project. If you do, it will get all mixed up between the
two of them and Bad Things will happen.
Tile
Available-
Tiles-
Element
Tile Tile
AvailableTiles
phead
Memory managed
y AvailableTiles
Memory managed by
AvailableTilesElement
Available-
Tiles-
Element
Available-
Tiles-
Element
Part Zero [Optional but recommended]: Add a Copy Constructor to the Tile Class [0%]
It will be helpful in Part A if you have a copy constructor for the Tile class. You will add one line to the
Tile.h file and one function to the Tile.cpp file.
Add the prototype for the copy constructor to Tile.h; place it with the public member functions:
Tile (const Tile& original);
Add the following function to Tile.cpp:
Tile::Tile(const Tile& original)
{
genus = original.genus;
species = original.species;
owner = original.owner;
}
Adjust the names of the three member fields to match the names of your member variables in the Tile
class.
Part A: Change the Board Class [40% = 30% test program + 10% code]
In Part A, you will change the implementation of the Board class to use dynamically allocated memory
for the tiles. You will also add a class invariant requiring that none of the pointers are nullptr (or
NULL). Apart from explicitly listing the copy constructor, destructor, and assignment operator, the
interface for the class will not change.
Warning: Your Board class must use dynamically allocated memory for the tile. If it does not, you will
eceive 0/40% for Part A.
By the end of Part A, your Board class will have the following public member functions:
Board ();
Board (const Board& original);
~Board ();
Board& operator= (const Board& original);
void print () const;
const Tile& getAt (const CellId& cell_id) const;
void setAt (const CellId& cell_id,
XXXXXXXXXXconst Tile& value,
XXXXXXXXXXunsigned int owner);
You will also have the following private member functions:
void printColumnNameRow () const;
void printBorderRow () const;
void printEmptyRow () const;
void printDataRow (int row) const;
void deleteAllTiles ();
void copyAllTiles (const Board& original);
bool isInvariantTrue () const;
Perform the following steps:
1. Change the declaration of your Board class so it contains a 2D a
ay of tile pointers instead of a
2D a
ay of tiles. Update the function implementations to call tile functions using a
ow
notation.
Example: Everywhere that you use dot notation to call a function, e.g.,
tile.function(); change it so that you have tile->function(); This idea
also applies if the function has parameters.
Note: You may want to name your pointer variables differently so you don't get them
mixed up with the normal kind of variable. For example, if your a
ay used to be named
data, it could be renamed to p_data or ptr_data.
2. Update the default constructor to allocate the tiles dynamically using the new command.
Reminder: The new command yields a pointer to the new memory space.
3. Update the setAt function. It should start (after the precondition) by deallocating the tile at
the specified cell. Then it should dynamically allocate a new tile for the specified cell.
Hint: Use the new command in association with the Tile copy constructor to create a
copy of the tile that is passed as a parameter. (If you do not provide the Tile copy
constructor, it will be provided automatically by C++). The syntax to initialize a pointer
named pb to point to a new Box (not a real type) that is a copy of an existing Box
named b1 is:
Box *pb = new Box(b1);
Hint: You should save the pointer returned by the new command. You should save it at
the specified cell in your 2D a
ay of pointers. This can be done with a simple
assignment statement; you do not need to put & or * in front of the pointer.
Comment: It is also permissible to use the Tile initializing constructor instead of the
Tile copy constructor. If you do it this way, you will need to set the owner field.
Reminder: Deallocation is performed with the delete command. The delete
command must be given a pointer to the memory space that is being deallocated.
4. Add an implementation for the