Show Lecture.PetPeeves as a slide show.
CS253 Pet Peeves
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.
- In ANSI C++, main() returns an int. Period.
- Some compilers accept void main() as a non‑standard extension.
- However, int main() is standard, so it works everywhere.
- It’s shorter, too.
- This ain’t Java.
endl vs. '\n'
cout << "Scarecrow" << endl;
cout << "Tin Man" << '\n';
cout << "Cowardly Lion" << "\n";
Scarecrow
Tin Man
Cowardly Lion
- endl and
'\n'
are not the same.
cout << endl
means cout << '\n' << flush
.
- flush means to send the buffered output to the ostream
(output stream).
- endl means emit
'\n'
and then flush the output.
- Don’t flush the output every time—it’s inefficient, and confuses
the reader. “Why is the program flushing now?”
- Output is flushed when the ostream is closed—usually just fine.
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
- Which is faster? Smaller? More readable?
- What is most important?
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
- Which is easier to understand & modify?
- Besides, who says that all computers use ASCII?
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
- 5280 × 12 is 63360, not 63660.
- I lied, to simulate a typo.
- Did anybody notice?
- How many years would that bug have lain waiting in the code?
- The civilized countries of the world use the
metric system.
- U-S-A!
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';
140726102152516
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 s = "Jack Applin";
cout << "My initials are " << s[0] << s[5] << '\n';
My initials are JA
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?”.
ifstream in("/etc/hostname");
int count=0;
while (!in.eof()) {
string s;
getline(in, s);
cout << ++count << ": " << s << '\n';
}
1: beethoven
2:
.eof()
means “Did the previous read fail?”.
ifstream in("/etc/hostname");
string s;
int count=0;
while (getline(in, s))
cout << ++count << ": " << s << '\n';
1: beethoven
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 is not equivalent to “produce an error”.
- The compiler does not throw errors—it produces error messages.
- Dividing by zero does not throw anything (but it could).
- Dereferencing a null pointer doesn’t throw (it could).
- On the other hand, this is defined to throw an error:
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!”