What EECS 183 and 280 didn't mention
There’s a set of common coding and testing mistakes that incoming students make. You can save yourself a lot of headache by reading about them now, rather than being confused later.
Coding
Exiting the program
How do you exit the program? The first idea that may come to mind is to call
exit(0)
(or exit(1)
, if appropriate).
If you call exit
, destructors will not be run. This means that you may not
free memory in those destructors, and the autograder may detect a memory leak.
(For example, if you have a vector
and call exit
, the vector
will not
delete its underlying array.)
You should structure your program in such a way that you can return 0
from
main
instead, which will allow destructors to run.
Iterators and auto
We encourage the use of C++14 in this class. One feature of C++14 is auto
,
which lets you omit types in many cases. (This feature is available since
C++11). In particular, avoid typing out long container iterator declarations:
Explicitly typing out these declarations is tedious, difficult to refactor, and
inevitably causes at least one student to have confusing compiler errors
relating to modifying a member vector
inside a const
member function.
Instead, write this:
This is shorter, won’t break your code when you change the type of myvec
, and
will automatically handle const
issues. See also range-based for
loops for an even better way of doing it.
Range-based for loops
As of C++11, you can use “range-based for loop” syntax to iterate through a container:
This automatically does the hard work of dereferencing iterators for you. Notice
that num
is an int
, not an iterator. When possible, use this syntax as it is
the shortest and easiest to read.
Make sure to pass your for-loop variable by reference or const reference if applicable:
Using break
The EECS 183 style guide forbids using break
to terminate loops. There’s
evidence to suggest that this doesn’t actually help code clarity: see Code
Complete 2, Chapter 16: Controlling Loops, or the referenced study by Soloway,
Bonar, and Ehrlich (1983), which both outline how using break
can enhance the
readability of your code.
If you have examined both arguments and still opt not to use break
, which is a
fine viewpoint to hold, you absolutely must not use hacks like this to terminate
your loop early:
This is only ever worse than break
, since it’s fragile (changing the loop
condition can cause your code to, ehm, break) and its significance can be
unclear. At this point, you should just use break
.
Reading input
The C++ input routines may not be the most intuitive at times. Unfortunately, it’s easy to accidentally produce something that works on your machine but then fails on the autograder.
The wrong way to read input
This code is buggy. Can you see why?
The problem is that cin.good()
doesn’t return false
until an operation has
failed. That means for the last iteration, it will try to read a value into
foo
and fail, without you realizing it! Running with input like 1 2 3
may
cause output like this:
An extra entry has appeared! In practice, your program may do unusual things
like duplicate the last entry or just crash. (valgrind
didn’t even detect this
when I tested this program.) You will likely fail most test cases on the
autograder if you’ve done this.
The right way to read input
Instead, combine the loop condition and the input reading operation:
This causes the body of the loop to execute only if we successfully read in all of our desired variables.
If for some reason the above approach isn’t appropriate for your code, you can fall back on checking the status of your input stream after trying to read from it.
Testing
Copying from the spec
You must not copy strings directly from the PDF. These often contain invisible characters, which your program will choke on. Instead, type strings into your editor manually. (Or, if the test file is available on Ctools, use that.)
Using Windows to edit files
Windows and Unix systems use different linebreaks. Windows uses a sequence of two characters (carriage return followed by line feed, or CRLF), while Unix uses just one (line feed, or LF).
If you are creating test files on Windows, you may accidentally create a file that uses Windows linebreaks, which your program may not be equipped to deal with. If you try to submit it to the autograder as a test case, the autograder may reject it for being invalid.
Checking for Windows linebreaks
To see if your test file has Windows linebreaks, you can run this command:
This counts the number of Windows linebreaks. If it produces a number greater than zero, then you’ll need to remove linebreaks.
Removing Windows linebreaks
The simplest way is to run dos2unix
on your test file:
If you don’t have dos2unix
installed, you can do something like this: