C++ Distilled
by Ira Pohl
Addison-Wesley ISBN 0-201-69587-1
C++ Distilled: A Concise ANSI/ISO Reference and Style Guide is a concise roadmap and style guide to C++ and at just over 200 pages it is slim and easy to use.
C++ Distilled selectively previews the proposed ANSI standard C++ language and includes many programming tips. It is easily used with any C++ programming book, but is especially suitable when used with one of my other books, Object-Oriented Programming Using C++, Second edition, C++ for C Programmers, Second or Third Edition, C++ for Pascal Programmers, Second Edition or C++ for Fortran Programmers.
Each section has the syntax, semantics, and examples of the language element and there are end-of-section style and programming tips. Heuristics and style tips provide experience-based suggestions on how to properly use a language feature.
Most programming is done by imitation of existing code and idioms. It is far easier to see a typical template than to read a 30-page description by language lawyers on all the intricacies. Therefore, the examples both within the book, and accessible at Addison Wesley Longman's website, are intended to exhibit good programming style. These examples use Dr. P's prescriptions and programming tips which are a distillation of considerable professional practice.
This book is a roadmap so that you do not get lost in the ANSI C++ byways. Although it is not a substitute for the ANSI standard, which is approximately 700 detailed technically dense pages, most programmers do not need such detail. Indeed, many of the features detailed in the standard are highly specialized and little used. Most programmers need to be able to quickly review some syntax or semantics that they have not recently used. C++ has many recent additions including STL, namespaces, RTTI, and the bool type. These can be used readily by someone already proficient in basic C++, but most books have yet to treat these topics. This book can provide a handy guide to these new constructs. Especially useful should be basic examples and information on STL container classes and generic algorithms.
You can buy this book online through Barnes and Noble.
The C++ code examples in the book are available in several forms. To get to the unpacked version for any system, or to get individual program files, you can use the FTP directory (www.cse.ucsc.edu/~pohl/DRP/). Files are also available in zip form for Windows users and compressed tar form for UNIX users.
Additional C++ Code Examples
Ira has provided additional code to demonstrate dynamic cast, complete clock program, multiple inheritance, mutable members, string constructors, and rvalue vs. lvalue.
Errata
Changes made in later printings are followed by a comment indicating the date.
Caveats: Some standard libraries may have been modified since this book was written and the function prototypes may differ from what is available on your compiler. Check your compiler vendor for the correct prototypes.
Notations:
p425 means page 425
+8 means 8 lines from top
-7
means 7 lines from bottom
If you encounter errata in this book not listed here, please contact Ira Pohl via email at pohl@cse.ucsc.edu with your errata. You will be cited in the correction if you are the first to report it.
Acknowledgements: Thanks to George Belotsky for giving me a first detailed list of errata. Thanks also to Jeffery Peden for his comments.
Needs to be: The examples both within the book, and accessible at Addison-Wesley's web site are ...
(The above correction has been made in printings after December 1997)
Needs to be: "\nGreatest Common Divisor"
(The above correction has been made in printings after December 1997)
Needs to be: long constants have greater range ...
Needs to be: '\0' on table entry 1
'O' 'O' 'P' ' ' '4' 'M' 'E' '\0' on table entry 2
"This is a single string, " on table entry 4
(The above correction has been made in printings after December 1997) p11 (C. L. Tondo) line -5: The closing ] in bus_stops[i] is in the wrong font. s
Needs to be: bus_stops[i]
(The above correction has been made in printings after December 1997)
Needs to be: typedef int BOOLEAN;
(The above correction has been made in printings after December 1997)
Needs to be: typedef char* c_string;
Needs to be:
namespace LMPinc { int n; namespace LMPdolls { //inner namespace int sq(){ return n * n; } //LMPinc::n void pr_my_logo(); } void LMPdolls::pr_my_logo() { cout << "Dolls by Laura" << endl; } }
(The above correction has been made in printings after December 1997)
Explanation: The linkage on inline has been changing. Here is what Steve Clamage of the ANSI committee stated in an email:
"The ARM said inline functions had static linkage, but didn't say what the linkage of inline class member functions was. For some time now, the draft standard has said that declaring a function inline does not affect its linkage, and that functions have external linkage unless declared static. If a function has external linkage, there is only one copy in the entire program of any of its local static objects. Existing books and compilers may have been written to earlier versions of the draft, and thus might not correspond to the current version. This aspect of inline functions is not going to change, given the schedule for publishing a final standard."
This change I believe affects inline explanation in most books. Proviso, this change may not yet have been implemented - so check your compiler. Better yet avoid situations where this can be a factor.
(No correction to the text needed.)
Needs to be: ! ~ &
(The above correction has been made in printings after December 1997)
Needs to be: int a = -5, b = 3, c = 0;
(The above correction has been made in printings after December 1997)
Needs to be: *q = i;
(The above correction has been made in printings after December 1997)
Needs to be: q =
(The above correction has been made in printings after December 1997)
Needs to be: *p = 7; *p is lvalue of a, so a is assigned 7
(The above correction has been made in printings after December 1997)
Explanation: The ANSI standard calls for new to throw the bad_alloc exception to indicate failure. The Borland 5.0 compiler throws xalloc. Many systems still do not throw exceptions, but instead return the null pointer value. Even where a system has migrated to the exception throwing behavior the programmer can use set_new_handler(0) to retain the older non-exception null pointer style.
(No correction needed to the text.)
Needs to be: The three lines on the right hand side of the table:
deletes the object pointed at by ptr
deletes the object pointed at by p[i]
deletes a vector of objects pointed at by p
(The above correction has been made in printings after December 1997)
Needs to be:
default: ++j; }
(The above correction has been made in printings after December 1997)
Needs to be: declarations allowd in the first component
Needs to be:
if (temperature >= 212) cout << "Above Boiling!\n"; else if (temperature >= 32) cout << "Above Freezing!\n"; else cout << "Boy it's cold " << temperature << endl;
(The above correction has been made in printings after December 1997)
Explanation: Yes the fragment assumes n >= 1), could have used documentation or assertion.
(No correction to the text needed.)
Needs to be:
//stats finds a data sets average, max and min. double stats(const double data[], //data input int size, double& max, //maximum element found double& min) //minimum element { double sum = max = min = data[0]; for (int i = 1; i < size; ++i) { sum += data[i]; if (data[i] > max) max = data[i]; else if (data[i] < min) min = data[i]; } return sum/size; }
(The above correction has been made in printings after December 1997)
assert (k > 1); //k must be at least 2 if (k == 2)
(The above correction has been made in printings after December 1997)
Needs to be: This makes them accessible solely to member and friend functions of the same class.
(The above correction has been made in printings after December 1997)
Explanation: This is an excellent expansion on the prescriptions. Because this would affect pagination, we are unable to add it to the text unless a major revision is done.
(No correction to the text is needed.)
Needs to be: friend complex operator+(complex, complex);
(The above correction has been made in printings after December 1997)
Needs to be: { this -> tick(); return *this; }
(The above correction has been made in printings after December 1997)
Needs to be: friend ostream& operator <<(ostream&, const vect&);
(The above correction has been made in printings after December 1997)
Needs to be: return *this
Explanation: It is the style of this book to not use parentheses with a simple return argument.
(No correction to the text is needed.)
p84 (Paul Sevinc)
salary has no constructor. The following line should be added immediately after the public declaraion:
salary(const int b) {b_sal = b; your_bonus = 0; }
Needs to be: person(const char*, int, unsigned long);
On P.86, in your example mutable.cpp, the function person::bday() must be declared const in order for the compiler to permit it to be called via the const object ira.
With or without mutable, a const object can only invoke const member functions.
If you change it to:
void bday() const { ++age;}
The program compiles and the mutability point is made.
Needs to be:
The indicated change corrects the problem. The following code is a small variation on the book that incorporates the correction.
#include < iostream > #include < string > using namespace std; class person { public: person(const string n, int a, const unsigned long ss) :name(n), age(a), soc_sec(ss){} void bday() const {++age;} void print() const { cout << name << " is " << age << " years old with SSN " << soc_sec << endl; } private: const string name; mutable int age; const unsigned long soc_sec; }; int main() { const person ira("ira pohl", 38, 1110111UL); ira.print(); ira.bday(); ira.print(); }
Needs to be:
class my_string { public: my_string() : len(0) //default constructor { s = new char[1];assert(s != 0); s[0] = 0; } explicit my_string(int n); //disallow conversion my_string(const my_string& str); //copy constructor my_string(const char* p); //conversion constructor ~my_string() { delete []s; } my_string& operator=(const my_string& str); my_string operator+(const my_string& str); friend ostream& operator<<(ostream& out, const my_string& str); void concat(const my_string& a, const my_string& b); private: char* s; int len; }; my_string::my_string(const int n) { s = new char[n + 1]; assert (s != 0); s[0] = 0; len = n; }(The above correction has been made in printings after December 1997)
Needs to be: return *this;
(The above correction has been made in printings after December 1997)
Needs to be: char * str = ...
Needs to be:
vect_bnd(const vect_bnd& v); //copy constructor vect_bnd(const vect& v); //conversion constructor ..... //conversion constructor vect_bnd::vect_bnd(const vect& v) : vect(v), l_bnd(0), u_bnd(size - 1) { } //copy constructor vect_bnd::vect_bnd(const vect_bnd& v) : vect(v),
(The above correction has been made in printings after December 1997)
Needs to be:
int ub() const { return u_bnd; } int lb() const { return l_bnd; }(The above correction has been made in printings after December 1997)
Needs to be: class Base { .....}; class Derived:Base { ..... }; void fcn(Base* ptr) { Derived* bptr = dynamic_cast = < Derived* >(ptr); In this example, the case converts the pointer value ptr to a Derived*.
(The above correction has been made in printings after December 1997)
Needs to be: out << endl << stu.name << ", " The ostream argument out is clearly intended here.
(The above correction has been made in printings after December 1997)
Needs to be:
template < class T >
class matrix
{ public: friend void foo_bar();
//universal friend vect< T >product(vect< T
> v); //instantiated ····· };
Explanation: By convention friends are stylistically considered part of the public interface of the class. However there is no programming or semantic distinction when friend function are listed in non-public access of a class.
(The above correction has been made in printings after December 1997)
Needs to be:
//templates for vect with associated iterator class #include < iostream.h > #include < assert.h > //for assert < class T > class vect_iterator; template < class T >vect { public: //constructors and destructor typedef T* iterator; explicit vect(int n = 10); //default constructor vect(const vect& v); //copy constructor vect(const T a[], int n); //from array ~vect() { delete [] p; } iterator begin(){ return p;} iterator end(){ return p + size;} T& operator[](int i) const; vect& operator=(const vect& v); friend vect operator+(const vect& v1, const vect& v2); friend ostream& operator<<(ostream& out, const vect& v); friend class vect_iterator< T >; private: T* p; //base pointer int size; //number of elements }; //default constructor template < class T > vect < T >::vect(int n): size(n) { assert(n > 0); p = new T[size]; assert(p != 0); } //copy constructor template< class T > vect < T >::vect(const vect< T >& v) { size = v.size; p = new T[size]; assert (p != 0); for (int i = 0; i < size; ++i) p[i] = v.p[i]; } //Initializing vect from an array template< class T > vect< T >::vect(const T a[], int n) : size (n) { assert (n > 0); p = new T[size]; assert (p != 0); for (int i = 0; i < size; ++i) p[i] = a[i]; } //overloaded subscript operator template< class T > T& vect< T >::operator[](int i) const { assert (i >= 0 && i < size); return p[i]; } //overloaded output operator template< class T > ostream& operator<<(ostream& out, const vect< T >& v) { for (int i = 0; i <= (v.size-1); ++i) out << v.p[i] << '\t'; return (out << endl); } template< class T > vect< T >& vect< T >::operator=(const vect< T >& v) { assert(v.size == size); for (int i = 0; i < size; ++i) p[i] = v.p[i]; return *this; } template< class T > vect< T > operator+(const vect< T >& v1, const vect< T >& v2) { assert(v1.size == v2.size) ; vect< T > sum(v1.size); for (int i = 0; i < v1.size; ++i) sum.p[i] = v1.p[i] + v2.p[i]; return sum; } template< class T > void init_vect(vect< T >& v, T start, T incr) { for (vect< T >::iterator p = v.begin(); p != v.end(); ++p) { *p = start; start += incr; //operator+= defined for T } } int main() { vect < double > v(5), t(5); vect < double >::iterator p ; init_vect(v, 1.5, 1.0); cout << "initial vect values\n"; for (p = v.begin() ; p != v.end(); ++p) cout << *p << " , "; cout << endl; t = v; //test assignment v = v + t; //test addition cout << "\n After doubling the values backward are\n"; p = v.end(); do { --p; cout << *p << " , "; } while (p != v.begin()); } Explanation: In template code what is not generated may not fail syntactically. In printing 1, the existing code did not test the incorrect assignment and addition code templates. Also for some reason in main(), vect< double > got mutated into vector < double >. I apologize for these multiple errors in the code. (The above correction has been made in printings after December 1997)
Needs to be: return p[i];
(The above correction has been made in printings after December 1997)
Needs to be: return *this;
(The above correction has been made in printings after December 1997)
Explanation: Yes, this section needs to be beefed up. The Teale (see p190) IOS93 is exhaustive, but somewhat out of date.
(No correction to the text will be made since it would cause repagination.) In later editions this might be modified.
Needs to be: static_cast < suit >(n / 13);
Explanation: Old style casts are very poor style and considered obsolete.
(The above correction has been made in printings after December 1997)
Needs to be: The overloaded >> get from operator ...
(The above correction has been made in printings after December 1997)
p135 (C. L. Tondo) line -8: Semicolon missing after function
Needs to be: int good():
(The above correction has been made in printings after December 1997)
Needs to be: operator void*() const;
(The above correction has been made in printings after December 1997)
Explanation: Both stdio and iostream should be synchronized if both are working with the same streams. Otherwise, mixing the two forms of IO should not cause a problem.
(No correction to the text needs to be made.)
Needs to be: class
(The above correction has been made in printings after December 1997)
Needs to be: class
(The above correction has been made in printings after December 1997)
Needs to be: void reverse(... (The above correction has been made in printings after December 1997)
"less" should be "lesser" in the table
Needs to be: s1.insert(2, s2); // s1 " I 7 years old am "
(The above correction has been made in printings after December 1997)
The changes are listed below:
p177 line 2: seven constructors
Needs to be: six constructors
p177 line 3-4: Two conversions were removed from the standard. Delete sentence "Two of these ..."
p177 String Constructor Members table entries 3 and 5: Two conversions were removed from the standard. Delete
string(const vector...) string(size_t size, ...)
p177 String Constructor Members table: One conversion was added to the standard. Insert in place of string(const vector...) string(InputIterator b, InputIterator e) constructor from the InputInterator range b to e
p177 Last Item in String Constructor Members table has order of arguments reversed. string(char c, size_t n = 1) is incorrect and cannot have the default argument. Needs to be: string(size_t n, char c)
p178 Third table entry from bottom of String overloaded Operator Members, operator vector< ... should be removed
p178 line -3 order of arguments reversed. append(char c, size_t n = 1) is incorrect and cannot have the default argument.
Needs to be: append(size_t n, char c)
p179 line 8 has order of arguments reversed. assign(char c, size_t n = 1) is incorrect and cannot have the default argument.
Needs to be: assign(size_t n, char c)
p179 line -5 has order of arguments reversed. insert(char c, size_t n = 1) is incorrect and cannot have the default argument.
Needs to be: insert(size_t n, char c)
p179 line 8 - needs another assign at end of assigns list
Needs to be: string& assign(InputIterator b, InputIterator e);
p179 line -4 needs 3 more inserts at end of inserts list
Needs to be:
iterator insert(iterator p, char c); iterator insert(iterator p, size_t n, char c); void insert(iterator p, InputIterator b, InputIterator e);
p180 Second table entry in String Members table has string& replace(pos, n, c, rep = 1); The rep argument has been removed.
Needs to be: string& rplace(pos, n, c); and the comment "repeated rep times" needs to be removed.
p180 Third table entry from bottom in String Members table has comment returns the private member res; the first function resets this which needs to be modified.
Needs to be: allocates memory for string; returns the size of the allocation
p180 Third and fourth table entries in String Members table and their explanations should be removed. The two items for removal are: char get_at(pos) const; and void put_at(pos, c);
p181 line 3 has int compare (const char* p, size_t pos) const which needs a default value on last argument.
Needs to be: int compare (const char* p, size_t pos = 0) const
p181 line 3 has int compare (char c, size_t pos, size_t rep = 1) const; which must be removed altogether.
(The above correction has been made in printings after December 1997)