C plus plus:Modern C plus plus:Wall of Shame

From GPWiki
Jump to: navigation, search

Modern C++ : Going Beyond "C with Classes"

Unfortunatly, C++ resources tend to be rather bad. While nearly all introduce material in, what is in my optinion, a sub-optimal order, not all of them contain downright mistakes. The Wall of Shame enumerates those books and articles that have outright errors. As a reminder that you should think about things you read, the Pitfalls section lists less serious errors.

The date of discovery of the error is included along with each. If you find that the issue has been corrected, please provide an indication of where the error is fixed (link to errata, a new revision number, link to the fixed article, etc) and move it to the Reformed section below.

Wall of Shame

Informit's C++ Reference guide (21 May 2006)
In Choosing the Right Container, Part III, one finds the following text:
Let's look at a concrete example of a map that contains a pair of strings, the first of which is a name and the second one is an e-mail address. We create the map like this:
#include <map>
#include <string>
map <string, string> emails;
To add an item to a map, use the subscript operator:
emails["J. Horvath"]="jhorvath@mail.com";
If the map already contains the key "J. Horvath", the current associated value remains unchanged:
emails ["J. Horvath "]="newaddr@com.net"; //has no effect
To give him the benefit of the doubt, we'll assume that he honestly missed that space and was mislead by the typo, not jump to the conclusion that he has no idea what he's talking about.
However, if you try what he obviously meant:
emails["J. Horvath"]="newaddr@com.net";
You'll find that, yes, the associated value does change.
Informit's C++ Reference guide (21 May 2006)
In the soapbox, in the Why I Hate C++ Cast Operators rant, you'll find the following:
int n;
double d=15.95;
int n= static_cast<int> (d);
It is correctly noted that this will not compile. However, later he suggests that changing the last line to
int n= *reinterpret_cast<int*> (&d);
and notes that "This version compiles without a problem". Unfortunately, he apparently didn't even bother trying to compile it, since it quite obviously doesn't. You cannot define the variable n twice. Trying to compile the initial example gives the following error message, in Comeau:
ComeauTest.c(5): error: "n" has already been declared in the current scope
int n = static_cast<int> (d);
Why anyone would think that this error message implies a problem with the cast operators, I don't know, especially since the same error will appear with the suggested "fix".
Informit's C++ Reference guide (21 May 2006)
In Create Objects on Pre-Allocated Memory Using Placement-new, one finds the following text:
C++ guarantees that the memory returned from new meets the strictest alignment requirements for every type of object. Therefore, you can use a dynamically allocated char array as the basis for constructing any other type of object.
No, it doesn't. new is only guaranteed to be aligned for the type of data that the programmers called it with, in this case char. Additionally, aliasing rules say that no pointer type can alias memory allocated for char's (with the exception of signed char* or unsigned char*).
The correct way to do the task is to use operator new:

/* // WRONG: char * raw_mem = new char [sizeof (Timer)];

  • /

// Correct: void *raw_mem = ::operator new( sizeof(Timer) );

operator new is what std::allocator uses to allocate memory without constructing.
Informit's C++ Reference guide (21 May 2006)
In Create Objects on Pre-Allocated Memory Using Placement-new, one finds the following text:
Placement new is -safe; unlike ordinary new, it doesn't throw.
Presumably that's supposed to read "exception-safe", but that's inconsequential. While it's true that (the default) placement new will not throw because of running out of memory, it can still throw if the constructor throws. Since we're not provided the implementation of the constructor, one must assume that it could infact throw.
Of note is that the constructor is passed a char*. If a member std::string is initialised with that char*, which is certainly plausible, that initialisation could run out of memory and throw.
Informit's C++ Reference guide (22 May 2006)
In POD (Plain Old Data) and Non–POD Objects, one finds the following text:
A POD object has one of the following datatypes: a built-in type, pointer, union, struct, array, or class with a trivial constructor.
Almost right, but something with a user-defined operator= or user-defined destructor isn't a POD, even though it can match the requirements specified in the above quotation.

Pitfalls

Informit's C++ Reference guide (21 May 2006)
In Extending <iostream> to Support User-Defined Types, there is the following text:
Remember also to place the endl manipulator at the end of the insertion chain to force a buffer flush.
Library code, stylistically, shouldn't be forcing you to have a '\n' there. The person outputting the object should be able to decide whether (s)he wants the '\n' or not and is perfactly capable of adding it himself/herself. More importantly, even if you do decide you want to force the '\n', you most certainly do not want to force the flush. For something as simple and plausible as outputting a number of students to a file, flushing the file after each student's name will unnessesarily slow down the output, which is already one of the slowest operations on modern computers.
Informit's C++ Reference guide (21 May 2006)
From the "did anyone even proof-read this?" file, in Extending <iostream> to Support User-Defined Types, there is the following text:
Overloading cin's <<
At this point you're probably wondering whether it's possible to extend cin as well, so that it can read an entire object from the standard input in a single cin expression. The answer is Yes. Although this technique is less commonly used, you can define an overloaded version of operator << that reads the values of student's data members from the standard input
I was under the impression that one used >> for read operations...

Reformed

None yet :(