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
-
optional
andnullopt
- 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 string
s. 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
cout
cerr
endl
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
+v
to 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. Makefile
s 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 thedwarf4
format -
-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
hpp
file in the command since they are already there via#include
s in the.cpp
files.
- 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:
-
-c
if you want to make an object file with this command, and then the.cpp
source for the.o
file -
-o target_name
if you are creating an executable (full program) from this command, wheretarget_name
is the name of the thing you want to build. You follow this with a list of all the.o
files 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
.o
file then it should be the corresponding.cpp
file and any local.hpp
files it includes. - If yo uare making an executable, it should be made of all the
.o
files 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_suite
to build with the sources:test_vec.o
andvec.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