Goals
- to better understand how arrays are implemented
- to work with building C++ classes
- to modify someone else's code neatly and effectively
including updating the documentation
Overview
In this assignment you will modify an existing vector class to allow the user
of the class to specify both the upper and lower bounds for the array.
For example, the user would be able to write
lbvector<char> v (-3,3,'m');
to declare a one-dimensional vector of char elements called v that has a lower
bound of -3, an upper bound of 3, and all the elements initialized to 'm'.
Referring to v[1] would not give the second element (as it would with the normal lower bound of 0).
Instead, v[1] refers to the fifth of the seven elements of v.
The picture below shows the vector without the initial values.
So when the user says v[-2], the indexing member function says
myZero[-2] to access the correct location.
Writing myList[-2] would access outside the allocated space.
Draw pictures to understand what is happening.
The text's discussion of virtual origins on p. 212-213 may be helpful because myZero is the virtual origin. Realize that C does pointer arithmetic using element sizes; therefore, myZero[i] is the same calculation as myZero+i. But you have to calculate myZero correctly whenever you allocate space.
In short, you should have a fully functional one-dimensional array class that allows the specification of upper and lower bounds. When you are done with this project, you should submit the final lbvector.h file as lab vector to liffick330. I need only the .h file that you modified.
Getting Started and Getting Finished
You will find the vector class definition in
~liffick330/assignfiles/vector/lbvector.h
along with a driver to help you more thoroughly test your implementation in
~liffick330/assignfiles/vector/driver.cxx
This driver will test some of the features of your new lbvector class.
It should compile with your modified lbvector.h file.
Make sure your class passes the tests before you submit it for grading.
Test it further on your own.
Copy the two files to your directory. You will modify the lbvector.h file because it contains both the class declaration and implementation. The version you copied does not compile with the driver. When you have it fixed, you should be able to compile it with the driver program to create a working test program. As an intermediate step, you may want to write a simpler driver that uses only the features you have implemented. Or comment out the lines that call things, such as the resize function, that you haven't yet implemented.
Be SURE you test your program thoroughly by declaring and manipulating many objects with extreme bounds. For example, try bounds in the billions or negative billions. Use ALL the constructors. Use ALL the operations. Beware that if you don't actually call a function it may not even be properly checked for syntax errors. Check that it aborts at appropriate places when out-of-bound subscripts are used. Check that your error messages make sense. Be very careful of off-by-one errors. Also, be sure to test the resize operation to verify that it keeps the common values appropriately.
Documentation
Update the documentation in the comments at the top to reflect
your changes.
Updating the documentation before you start changing the code
may help you better understand your task.
Update the examples to show how the class is used.
Include your name in the appropriate place.
Note that the functions have preconditions and postconditions.
Update them as appropriate.
I will count off a substantial number of points if the documentation
(comments and examples)
doesn't match the class.
Changes You Should Make
You'll need to make many of these changes before you can compile the class and driver together. You're changing the class's representation, and everything needs to work together. You can put off building the resize operation, copy constructor, and assignment operator.
Define instance variables. You will need to change and add to the instance variables to make this work. Carefully think about how the instance variables are representing the class. Draw pictures of various examples. In particular, you'll need a myZero instance variable which will be a pointer to where the zero'th element of the vector would be. As you write each member function, check that you set each instance variable to accurately reflect the class's state.
The class invariant is what must be true about the class (as seen in its instance variables) outside the member functions. Each member function can depend on the class invariant being true when it starts. It should ensure that the class invariant is true when it finishes. Check that every instance variable is set correctly in every member function.
For this lbvector class, the following could be the invariant:
myList points to the beginning of the allocated space
myZero points to where the element with index zero
would be if there were one
myLower is the lowest legal index
myUpper is the highest legal index
myCapacity is the number of elements allocated
myZero[myLower] is the same memory location as myList[0]
One consequence of this invariant is that in an empty vector, myUpper should be -1 rather than 0. If myUpper is (incorrectly) 0, 0 is a legal index and myCapacity is 1.
Fix the constructors so that they have 0, 2 or 3 parameters instead of 0, 1 or 2. The parameters are to be the lower index bound, the upper index bound, and the optional initialization value. It should construct the array so that it allows indexes between the lower and upper bounds inclusive. Make sure that the fill operation works correctly.
Fix capacity operation. Add upper and lower operations. These are easy fixes and additions after creating the instance variables.
Fix both subscript operations and the checkIndex operation so that they check the appropriate range and abort if the index is not within the lower to upper bounds inclusive. The error message should be accurate and informative. The subscript operation should be written in an efficient manner so that the amount of work per index operation in minimized. You must pre-calculate any constant parts of the expression in the constructor and save the value as an instance variable (myZero). NOTE: This means that you are to calculate the position of the logical zeroth element and save that pointer as an instance variable. You are absolutely NOT to translate the subscript into the subscript range of the allocated array each time you do a subscript operation. The subscript operation should not do ANY addition or subtraction of indexes.
Fix the resize operation so that it takes both a lower and an upper bound. It should copy any values whose index is in both the original and adjusted ranges. It should work so that if index i is in both ranges then theArray[i] will have the same value before and after the resize. Be sure to recalculate any precomputed values used in subscripting.
___ ___ ___ ___ ___ ___ ___
|23 |-3 |17 |12 |42 |-5 |2.2|
original bounds -3 3 |___|___|___|___|___|___|___|
-3 -2 -1 0 1 2 3
___ ___ ___ ___ ___ ___
| ? | ? |23 |-3 |17 |12 |
new bounds -5 0 |___|___|___|___|___|___|
-5 -4 -3 -2 -1 0
Make sure that the copy constructor works correctly.
Update the other functions to provide a usable class. Find the bugs before I do. This driver does not test everything I will test. In particular, build some simple programs that try to go out of bounds and check the edges. There is an example error driver in the same directory you found the starting files. Are your error messages appropriate? Is there an appropriate error message if the bounds are provided out of order?