Goals
- Introduction to C++ Classes & Some fundamental aspects of C++
- Dynamic Memory
- Destructors (RAII)
- Pointers as Arrays
- Exceptions
- References
- The fundamental datastructure
vector - Header-guards & Makefiles (cont.)
Collaboration
For assignments in CIT 5950, you will complete each of them on your own. However, you may discuss high-level ideas with other students, but any viewing, sharing, copying, or dictating of code is forbidden. If you are worried about whether something violates academic integrity, please post on Ed or contact the instructor(s).
Setup
Task 1. Setup your docker to gain access to a development environment for the course.
If you haven’t already, you need to follow the Docker Setup. We recommend you try and figure this out ASAP.
You need to do this assignment in the docker environment setup by the course. You should create a different directory in your docker environment to run your code, but you do not have to.
Once you are in docker, you must run the following commands to download the starter files for the project.
curl -o vec.zip https://www.seas.upenn.edu/~cit5950/current/projects/code/vec.zip
and
unzip vec.zip
after this you can ls again and see that we have the file vec.cpp, Makefile, vec.hpp, test_suite.cpp, catch.hpp and catch.cpp added to our local directory.
From here you can start working the assignment by opening the files we just created with vim, VSCode or another editor if you have one you prefer.
Instructions
Once you have followed the setup instructions, you should have a folder that contains the files for this assignment.
Note: you are restricted from using most of the standard C++ library in this assignment. See the section below on allowed functions for more.
Required Knowledge
This homework has you writing C++ code and most of what you need has been covered in lecture already. However, there are a few things you may have to wait for in lecture. Notably:
- exceptions
-
optionalandnullopt - references
- Destructors
- Copy Constructors
You may be able to figure out some of these topics on your own and some have been covered in recitaiton already.
You can also finish most of the homework assignment while ignoring exceptions and optional until it is covered in lecture. Just make pop_back return nullopt till it is covered.
Again: C++ (like C) doesn’t provide variables with a default initial value. When you declare a new variable be sure that you assign it a value.
For this assignment, you will be writing some code to implement a simplified version of the vector datastructure in C++. While a normal C++ vector can store any value, we will keep our implentation to storing strings. There should be some similarities to what you did in simple_string, but it is very important that we implement this structure outselves since it gives expereince with more C++ features and the vector is a fundamental data structure in programming, arguably more important than a hash-map. (Note: Some languages call a vector something else. Java: ArrayList, Python: list, Rust: Vec, etc.)
If you are stuck on anything related to C++ objects we encourage you to look at the relevant lecture materials.
We suggest you start by opening vec.hpp and reading the code and comments.
Once you have familiarized yourself with what is going on, you should open the (mostly) empty vec.cpp and provid an implementation for every function described in the vec.hpp header files. Your cpp file should #include the corresponding hpp file.
Allowed / suggested functions & headers
For this assingment you are allowed to write any helper functions you need, but you are restricted to using the following headers and the following functions. You do not need to use all of these, do what you think would be best for your code. If you do not see a function listed that you think should be ok to use, please ask and we can allow it or disallow it.
- string
std::string
- stdexcept
std::out_of_range
- iostream
coutcerrendl
Compilation
Header Files and Header Guards
For this assignment we gave you vec.hpp, which is a header file.
Header files contain the declarations of types and declarations of functions that are defined in the corresponding cpp file.
For your code to get full credit, you will need to add header guards like this to your vec.hpp, similar to what you did in simple_string.
If you have coded in C or C++ before you may be tempted to use #pragma once instead of header guards. While this is relatively common, it is not actually standard in C++ and can have varying details in different C++ compiler (or may not be supported by a compiler at all!). Thus we are not going to use #pragma once in this class)
Note that your submission will be partially evaluated on the number of compiler warnings. You should eliminate ALL compiler warnings in your code.
Makefile
You must also modify the provided Makefile to compile the code into a runnable test_suite.o.
We provide most of the makefile for you, and you will also note that the makefile includes steps for building catch.o and test_suite.o and then using it to compile your test_suite program.
Like the last assignment, you will have to build off of what we did in the makefile. This time you will need to make it build test_vec.o and vec.o from the corresponding cpp and hpp files and then use those to build the test_suite.
This is not as hard as it may sound! It may look scary, but you can do it!
Makefiles should have already been covered in a past class, but in-case you are stuck on it, here is a crash course.
Makefile Crash Course
Below is the template for a single “rule” in a Makefile.
target : source0 source1 source2 .... sourceN
(compiler) (flags) (input files)
Each rule is composed of:
- a target followed by a
: - after the
:there is a list of source files. - The next line starts with a tab
- (Note: your editor may insert spaces when you hit tab, but it MUST be a tab character. in vim you may have to type
ctrl+tab+vto insert a tab character)
- (Note: your editor may insert spaces when you hit tab, but it MUST be a tab character. in vim you may have to type
- After the tab you have some command that builds the target from the listed sources.
- this often looks like specifying a compiler, some flags and then the input files to the compiler
The target is just whatever file you want to build with this rule.
The source files are the files that this target depends on. Makefiles will recursively check if any source needs to be rebuilt before the a target is rebuilt.
Lets look at an example rule we provide you: catch.o. Note: You can assume this rule works
catch.o: catch.cpp catch.hpp
clang++-15 -g3 -gdwarf-4 -Wall --std=c++2b -c catch.cpp
This rule specifies how to build catch.o. It depends on catch.cpp and catch.hpp so if either of those files got updated before we type make in the terminal, then catch.o will be rebuilt.
On the next line we hav a tab character followed by: clang++-15 -g3 -gdwarf-4 -Wall --std=c++2b -c catch.cpp. This line is usually the line that scares people so lets break it down:
-
clang++-15: the compiler we use in this course -
-g3 -gdwarf-4: use maximum debugging info in thedwarf4format -
-Wall: turn on “all” compiler warnings -
--std=c++2b: use C++2b (which is C++23) -
-c: compile the result into an object file - everything else (in this case just
catch.cpp) is the ipnut file to the compiler.- Note: We never have to put an
hppfile in the command since they are already there via#includes in the.cppfiles.
- Note: We never have to put an
To simplify this for you, almost every compilation command in this class should start with the same part:
clang++-15 -g3 -gdwarf-4 -Wall --std=c++2b. Then you either add one of:
-
-cif you want to make an object file with this command, and then the.cppsource for the.ofile -
-o target_nameif you are creating an executable (full program) from this command, wheretarget_nameis the name of the thing you want to build. You follow this with a list of all the.ofiles that make the executable.
Sources for a target is either a list of .o files OR it is a list of .cpp and .hpp files.
- If you are making an
.ofile then it should be the corresponding.cppfile and any local.hppfiles it includes. - If yo uare making an executable, it should be made of all the
.ofiles that are needed to make the executable.
For your makefile in this assignment, you need to:
- Add a new rule to build
vec.o - Add a new rule to build
test_vec.o - Modify the
test_suiteto build with the sources:test_vec.oandvec.o - The new rules you add should use the same compiler and most of the same compiler flags as other rules.
- compile with extra information for a debugger and the dwarf 4 debugging rule
- have the “enable all warnings” option turned on
- use C++ version
c++2b
Testing your code
Valgrind
You need to test your submission on whether there are any memory errors or memory leaks. We will be using valgrind to do this. To do this, you should try running:
valgrind --leak-check=full ./test_suite
If everything is correct, you should see the following towards the bottom of the output:
==1620== All heap blocks were freed -- no leaks are possible
==1620==
==1620== For counts of detected and suppressed errors, rerun with: -v
==1620== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
If you do not see something similar to the above in your output, valgrind will have printed out details about where the errors and memory leaks occurred. We went over how to read valgrind errors some time in recitation or lecture in the first or second week.
Note that the last part of the valgrind command is just what we would input to run our program normally. You should try running your program on various inputs. (e.g. some valid and some invalid) to make sure it passes for all test cases.
Autograder
This assignment has an autograder to test the functionality of your vec object, but this mostly just runs the tests we provide. When you submit to gradescope (see below) it should run tests for you, but you are HIGHLY ENCOURAGED to run the test locally. Infact, if the code fails on gradescope in the test_suite it will not tell you much other than it failed. It will be up to you to debug it locally.
Submission
Please submit your completed Makefile, vec.cpp and vec.hpp to Gradescope