CS253: Software Development with C++

Spring 2021

Pet Peeves

Show Lecture.PetPeeves as a slide show.

CS253 Pet Peeves

made at imgflip.com

Guessing

Student: It doesn’t compile when I use ifstream.
Jack: Each class comes from a header file. You must include it.
Student:Is it <ifstream>?
Jack:You’re guessing.
Student:Is it <iostream>?
Jack:Stop guessing. Look it up in https://cplusplus.com or https://cppreference.com.
Student:I know! It’s <cout>!
Jack:sigh

Albert Einstein, they say, didn’t know the speed of sound, but knew where to look it up.

void main()

made at imgflip.com

endl vs. '\n'

cout << "Scarecrow"     << endl;
cout << "Tin Man"       << '\n';
cout << "Cowardly Lion" << "\n";
Scarecrow
Tin Man
Cowardly Lion

endl alternatives

cout << "Scarecrow"     << '\n'
     << "Tin Man"       << '\n'
     << "Cowardly Lion" << '\n';
Scarecrow
Tin Man
Cowardly Lion

cout << "Scarecrow\n"
     << "Tin Man\n"
     << "Cowardly Lion\n";
Scarecrow
Tin Man
Cowardly Lion

cout << "Scarecrow\n"
        "Tin Man\n"
        "Cowardly Lion\n";
Scarecrow
Tin Man
Cowardly Lion

cout << "Scarecrow\nTin Man\nCowardly Lion\n";
Scarecrow
Tin Man
Cowardly Lion

ASCII constants

There is no benefit to memorizing the ASCII table, at the cost of program readability.

char c1 = 65;     // Sure, this works.
char c2 = 'A';    // But so does this.
cout << c1 << c2;
AA

Doing work for the computer

Doing work for the computer is like cleaning up for the maid. I see code like this:

    inches = miles * 63660;

When I ask the student, “How’d you come up with that number?”, they say “I multiplied 5280 by 12 on a calculator.” Gosh—that sounds like something that the computer should be doing:

    inches = miles * 5280 * 12; // 5280 feet/mile, 12 inches/foot

Or, depending on how many places you do this:

    constexpr auto feet_per_mile = 5280,
              auto inches_per_foot = 12;
    inches = miles * feet_per_mile * inches_per_foot;

The compiler will fold the constant multiplication for you—it will do the multiplication at compile-time, not during program execution.

Pants on Fire

cout << 5280*12;
63360

Indentation

Indentation is often regarded as useless. As long as the program works, that’s all that matters!

Those of us who have to read and maintain your code disagree.

Casting

Casting is not magic.

char buf[] = "123";
long n = (long) buf;
cout << n << '\n';
140736311454948

If you use casting, then something is wrong. Think again.

vector/string methods

Java programmers love .at(), and refuse to learn about [].
.at() does error checking, [] usually doesn’t.

vector<int> v = {11,22,33};
for (size_t i=0; i<v.size(); i++)
    cout << v.at(i) << ' ';
for (size_t i=0; i<v.size(); i++)
    cout << v[i] << ' ';
11 22 33 11 22 33 

Do we need error checking in that code? Could i get out of range?

Similarly, for strings:

string name = "Boris";
cout << name << " starts with a ‘" << name[0] << "’\n";
Boris starts with a ‘B’

Not everything is a reference

You do not have to use new to create an object:

string s;
s.push_back('C');
s += 'S';
s += "U";
cout << s << '\n';
CSU

.eof() does not predict

.eof() does not mean “Will the next read fail?”. Instead, it means “Did the previous read fail?”.

ifstream in("/etc/hostname");
int count=0;
while (!in.eof()) {
    string s;
    getline(in, s);
    cout << "Line " << ++count << ": " << s << '\n';
}
Line 1: beethoven
Line 2: 

Instead, just trust getline() to return false upon failure.

ifstream in("/etc/hostname");
string s;
int count=0;
while (getline(in, s))
    cout << "Line " << ++count << ": " << s << '\n';
Line 1: beethoven

(Actually, it returns reference to the I/O stream, which evaluates as false if the stream is in a failure state.)

Boolean is hard!

It’s ok to use boolean values as values, not just in if and while:

char c = 'a';
bool vowel;
if (c=='a' || c=='e' || c=='i' || c=='o' || c=='u')
    vowel=true;
else
    vowel=false;
cout << boolalpha << vowel << '\n';
true
char c = 'a';
bool vowel = (c=='a' || c=='e' || c=='i' || c=='o' || c=='u');
cout << boolalpha << vowel << '\n';
true

Return is easy

return is not a function, so parentheses are not required:

int main() {
    cout << "Hello\n";
    return 0;  // Note lack of parens
}
Hello

throw

string s = "foo";
cout << s.at(9);
terminate called after throwing an instance of 'std::out_of_range'
  what():  basic_string::at: __n (which is 9) >= this->size() (which is 3)
SIGABRT: Aborted

And …

Equating “literally” and “figuratively”
“My head literally exploded!”
Regarding all odds as 50/50
“I might win the lottery, I might not. It’s 50/50.”
Confusing “strict“ or “harsh” with “unfair”
“The average on the midterm was 60%? That’s totally unfair!”
Unnecessary estimates that I don’t believe
“I have only two quick questions.”