Last week, I noted that textbook authors who revise their books have a natural tendency to add new material in a small number of places rather than integrate it. This tendency tends to make it harder to learn from the book, and it is particularly troublesome when the new material makes the language more abstract — as it has done fairly consistently over the nearly 30 years that I’ve been associated with C++.
Here is a small example of this phenomenon. The original idea behind adding classes to C was to make C++ classes upward compatible with C structures. In particular, in the early days of copy constructors (1984 or so), copying a class without an explicitly defined copy constructor would simply copy the underlying C structure. Programmers at the time talked about this operation as a “bitwise copy.” This behavior caused trouble in cases such as
struct Person { String firstname, lastname; };
There was no standard string library at the time, so I’m using the name String
to signify a user-defined class that implements variable-length character strings.
In this early version of C++, this class would be a disaster. The String
class presumably includes a pointer to the actual characters that constitute the string, so it will not do simply to copy this pointer as part of copying a Person
object. Doing so would cause those characters to be freed twice, once for the original Person
object and once for the copy. As a result, programmers in this version of C++ had to supply copy constructors explicitly:
struct Person { Person(const Person p): firstname(p.firstname), lastname(p.lastname) { } // and so on String firstname, lastname; };
Any teaching material based on that early version of C++ would have had to teach this programming technique, because even simple abstractions would lead to nasty bugs without the technique. Of course, the difficulty of programming in this way soon led to redefining C++’s default behavior in such cases: Instead of copying the underlying C structure, the C++ compiler would recursively copy the elements of the structure.
Imagine now that you are a textbook author. Throughout your book, your programming examples have dutifully used copy constructors that explicitly copy their classes’ data members. Now the language has changed, and all this code is no longer necessary. What do you do?
You could go through the entire book in detail, finding every example that uses one of these now unnecessarily complicated constructors, and either simplify the constructor in question or remove it entirely, as appropriate. Alternatively, you could add a chapter with a title such as Using The New Features that explains that a fair amount of the code in the rest of the book is no longer necessary and can be disregarded.
Although the second of these strategies is much easier for the author, the revised C++ Primer uses the first strategy. There are a number of places in C++11 that make it unnecessary to write code that used to be essential. This fact has resulted in some fairly significant changes to the order in which the book introduces some of its key ideas. Next week, we’ll take a look at a concrete example of such a change.