Your task is to use object-oriented programming to implement a vector-like
class called str_vec. One of it's major features is that it completely (and
correctly!) manages its own memory, similar to a vector<string>.
Put all your code for this assignment into a2.cpp. Implement all the requested methods and functions using the exact name and parameters. You can add other helper functions/methods if you need them.
Write a test function to automatically test each major method/function to ensure it is correct. Use either if-statements or assertions for the testing. Each test function should have approximately 5 tests (more complex/input code should probably have more).
Implement each of the following methods and functions. Use const, public,
and private whenever possible.
-
Implement a default constructor for
str_vec()that creates a newstr_vecof size 0 and capacity 10.Example:
str_vec arr; // arr is an empty str_vec of size 0 and capacity 10The capacity of
str_vecis the size of its underlying array. The size is the number of items in thestr_vecfrom the point of view of the user. -
Implement a destructor
~str_vec()that deletes the dynamic memory used by thestr_vec.Be sure your program has no memory leaks by testing it with
valgrind! -
Implement a constructor
str_vec(n, s)that creates a newstr_vecof sizenwhere each element is a copy of the strings. The capacity should be at leastn. Ifnis less than 1, usecmpt::errorto throw a helpful error message.Example:
str_vec arr(5, "cat"); // arr is str_vec of size 5, each entry containing the string "cat"
-
Implement a copy constructor
str_vec(other)that creates a newstr_vecthat is a copy of thestr_vecother.Example:
str_vec a(5, "<empty>"); str_vec b(a); // b is a str_vec of size 5 with each entry equal to the string "<empty>"
The capacity of
bshould be at least the size ofa.Both
aandbshould have their own underlying array. -
Implement an array constructor
str_vec(arr, n)that creates a newstr_vecthat is a copy of the array of strings namedarr, with sizen. The type ofarrin the constructor isconst char*[].Example:
const char* arr[] = {"red", "white", "yellow"}; str_vec a(arr, 3); // 3 is the length of arr // a is a str_vec of size 3 with entires "red", "white", "yellow"
The passed-in array should not be changed in any way. a should have its own
copy of arr.
-
Implement these getters:
-
size()andlength(): both return the number of strings in thestr_vec. Two methods are provided for returning the size as a convenience:length()is an alias forsize(). -
capacity(): returns the capacity of thestr_vec, i.e. the size of the underlying array. -
pct_used(): returns the percentage (from 0.0 to 1.0) of the underlying array that is in use, i.e. the size divided by the capacity.
Make sure that these are all
constmethods!Example:
str_vec empty; cout << empty.size() << ' ' // 0 << empty.capacity() << ' ' // 10 << empty.pct_used() << '\n'; // 0
Write three test functions, one for each method.
-
-
Implement these non-mutating methods:
-
to_str(): returns astringrepresentation of thestr_vec. Each string should be printed in "-quotes, and wrapped in {}-braces as shown in the example below. -
print(): avoidmethod that prints the string representation of thestr_vectocoutwithout a\nat the end. -
println(): avoidmethod that does the same thing asprint(), but also prints a\nat the end
Make sure these are all
const!Example:
str_vec arr(3, "cat"); string s = arr.to_str(); // s is the string {"cat", "cat", "cat"} arr.print(); // prints {"cat", "cat", "cat"} on cout (no \n at end) arr.println(); // prints {"cat", "cat", "cat"} on cout (\n at end)
For this question you only need to make a test function for
to_str(). For this assignment, it's okay if you check the results ofprintandprintlnmanually. -
-
Implement these methods:
-
get(i)is a getter that returns thestringat index locationiof thestr_vec. Just as with arrays, the first index location is 0. Make sure this isconst! -
set(i, s)is a setter that sets index locationito be a copy of strings.
Both methods should do bounds checking: use
cmpt::errorto throw a helpful error message if the passed-in indexiis less than 0, or greater thansize() - 1.Example:
str_vec arr(3, "cat"); arr.set(1, "dog"); // arr is now {"cat", "dog", "cat"} string s1 = arr.get(1); // s1 is "dog" string s2 = arr.get(2); // s2 is "cat"
Write test functions for both
setandget. -
-
Implement these mutating methods:
-
append(s)is avoidmethod that adds the stringsto the right end (the back) of thestr_vec, increasing the size by 1. -
append(sv)is avoidmethod that appends all the strings in thestr_vecsvto the right end (the back) of thestr_vec, increasing the size by the size ofsv.
For both methods, the underlying capacity should only be increased if necessary. When the capacity is increased, it should be doubled.
Example:
str_vec arr; // {} arr.append("apple"); // {"apple"} arr.append("orange"); // {"apple", "orange"} str_vec fruit; // {} fruit.append("pear"); // {"pear"} fruit.append("banana"); // {"pear", "banana"} arr.append(fruit); // {"apple", "orange", "pear", "banana"} arr.append(arr); // {"apple", "orange", "pear", "banana", // "apple", "orange", "pear", "banana"}
Write two test functions, once for each version of
append. -
-
Implement the
voidmutating methodcapitalize_all()that capitalizes all the strings instr_vecthat can be capitalized. A string can be capitalized if it is not empty, and the first character is one of the 25 lowercase letters a to z. Strings that can't be capitalized are left unchanged.For example, if the
str_vecais{"hat", " dog", "house boat", "Wall"}, then after callinga.capitalize_all()it will be{"Hat", " dog", "House boat", "Wall"}.This is a mutating method, so the
str_vecitself should be changed (no copies made). -
Implement the
voidmutating methodremove_first(const string& s)that removes the first occurrence ofsin thestr_vec. All the strings to the right are moved left one position to fill in the gap, and the size of thestr_vecis decreased by 1. Ifsis not in thestr_vec, then thestr_vecis unchanged.For example, if
str_vecais{"hat", "shoe", "hat"}, then after callinga.remove_first("hat"), it will be{"shoe", "hat"}. -
Implement the
voidmutating methodkeep_all_starts_with(char c)that keeps only strings that start withc, and removes any others.For example, if the
str_vecais{"hat", "book", "horse", "house", "Hot!"}, then after callinga.keep_all_starts_with('h')it will be{"hat", "horse", "house"}.The order of the strings after calling
keep_all_starts_withshould be the same as before calling it.If none of the strings start with
c, or thestr_vecis empty, then then thestr_vecis empty after callingkeep_all_starts_with. -
Implement these mutating methods:
-
clear()is avoidmethod that removes all elements from thestr_vecso its size is 0. Make this method as efficient as possible. The capacity can stay the same. -
squish()is avoidmethod that will, if necessary, re-size the underlying array so that the size and capacity are the same. The elements in the array are the same (and in the same order) after squishing as before.
Example:
str_vec arr; // {}, size 0, capacity 10 arr.append("a"); // {"a"}, size 1, capacity 10 arr.append("b"); // {"a", "b"}, size 2, capacity 10 arr.squish(); // {"a", "b"}, size 2, capacity 2 arr.clear(); // {}, size 0, capacity 2
Write test functions for both
squishandclear. -
-
Implement these functions (not methods!):
-
operator==(a, b)is aboolfunction that returnstrueif thestr_vecaand thestr_vecbhave the same elements in the same order, andfalseotherwise -
operator!=(a, b)is aboolfunction that returnstrueif thestr_vecaand thestr_vecbdon't have the same elements in the same order, andfalseotherwise
Example:
str_vec a(3, "cat"); str_vec b(3, "cat"); if (a == b) cout << "same\n"; // prints "same" if (a != b) cout << "different\n"; // prints nothing a.set(0, "feline"); if (a == b) cout << "same\n"; // prints nothing if (a != b) cout << "different\n"; // prints "different"
Write test functions for both
operator==andoperator!=. -
-
Implement a mutating method
sort()that re-arranges the elements of astr_vecinto alphabetical order.For example:
str_vec a; a.append("hat"); a.append("dog"); a.append("cat"); a.append("house"); cout << a.to_str() // {"hat", "dog", "cat", "house"} << "\n"; a.sort(); cout << a.to_str() // {"cat", "dog", "hat", "house"} << "\n";
This is a mutating method, so the
str_vecitself should be changed (no copies made).
Please put all your code into a2.cpp, and submit it on Canvas. Implement all the methods and functions exactly as described, otherwise the marking software will probably give you 0!
Submit only a2.cpp, and no other files. The marker will use the standard makefile to compile it, and a copy of cmpt_error.h will be in the same folder as a2.cpp when it's tested.
Before we give your program any marks, it must meet the following basic requirements:
-
It must compile on Ubuntu Linux using the standard course makefile:
$ make a2 g++ -std=c++17 -Wall -Wextra -Werror -Wfatal-errors -Wno-sign-compare -Wnon-virtual-dtor -g a2.cpp -o a2If your program fails to compile, your mark for this assignment will be 0.
A copy of cmpt_error.h will be in the same folder as a2.cpp when it's compiled, so your program can use
cmpt::errorif necessary. -
It must have no memory leaks or memory errors, according to
valgrind, e.g.:$ valgrind ./a2 // ... lots of output ...A program is considered to have no memory error if:
-
In the
LEAK SUMMARY,definitely lost,indirectly lost, andpossibly lostmust all be 0. -
The
ERROR SUMMARYreports 0 errors. -
It is usually okay if still reachable reports a non- zero number of bytes.
-
-
You must include the large comment section with student info and the statement of originality. If your submitted file does not have this, then we will assume your work is not original and it will not be marked.
If your program meets all these basic requirements, then it will graded using the marking scheme on Canvas.
- In a2.cpp, there is the commented-out function
austenTest()that you may choose to use to help test your class when it's done. You don't need to use it, and you can change it if you like.
- All code is sensibly and consistently indented, and all lines are 100 characters in length, or less.
- Whitespace is used to group related pieces of a code to make it easier for humans to read. All whitespace should have a purpose.
- Variable and function names are self-descriptive.
- Appropriate features of C++ are used, as discussed in class and in the notes. Note If you use a feature that we haven't discussed in class, you must explain it in a comment, even if you think it's obvious.
- Comments are used when needed to explain chunks of code whose purpose is not obvious from the code itself. There should be no commented-out code from previous versions.
- No unnecessary work is done.
- No unnecessary memory is used.
To get full marks, your functions must pass all the test cases the marker uses for that question. The marker may use test cases not given in the assignment.
-
Question 1-15, 2 marks each. 1 mark for the correct method/function, and 1 mark for a good testing function for that method/function.
A few of the questions have more than one function/method, and you should write a test function for each.
- -1 mark (at least) if your file does not have the correct name, or you submit it in the incorrect format.
- up to -3 marks if you do not include your full name, email, and SFU ID in the header of your file.
- a score of 0 if you don't include the "statement of originality in the header of your file.
- a score of 0 if you accidentally submit a "wrong" non-working file, and then after the due date submit the "right" file. If you can provide evidence that you finished the assignment on time, then it may be marked (and probably with a late penalty).