Show Lecture.PetPeeves as a slide show.
CS253 Pet Peeves
Guessing
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?
- Say what you mean!
- 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;
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.
- A-Ƨ-U!
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';
140732311785188
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"); // contains ONE line
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 a reference to the I/O stream, which evaluates
as false if the stream failed.)
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.
- With g++, dividing by zero doesn’t throw anything
(but it could ).
- With g++, 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
- How’d I know that? I read the string::at() documentation!
Crazy, huh?
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.”
- Thinking that “Standard” means “Official” in time zones:
-
“July 4, noon Eastern Standard Time”