Scott Meyers

Modification History and Errata List for Effective C++, Second Edition

Last Updated 31 August 2015
by Scott Meyers

Note: This document applies to only the second edition of Effective C++. Errata for other editions of the book are available as follows:

What follows are my notes on what I've changed in the second edition of Effective C++ since its original publication (i.e., since its first printing) and what I believe may need to be changed in future printings. Most of the changes (or prospective changes) are cosmetic and don't affect the technical content of the book. To distinguish those modifications that do affect technical material, I precede those entries with an exclamation mark ("!") and display them in red.

Each entry includes the following information:

The easiest way to use this list is to find out which of the book's printings you have (it's listed on the copyright page near the bottom), then go to the appropriate section of the list and read from that point forward. For example, if you have a copy of the third printing, the changes made to the first and second printings won't apply to you, because the changes will already be in place in your copy of the book.

I am always interested in bug reports and suggestions for improvements to Effective C++. To submit comments, send email to ec++@aristeia.com or write to the address listed on page xv of the book's preface.

To be assured of always having the most accurate version of Effective C++ at your fingertips, I encourage you to buy a copy of each printing :-).

The following changes were made for the third printing of the book. These changes apply to your copy of Effective C++, Second Edition only if it's the first or second printing.

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
    N/A    N/A   xix  Added apm to the acknowledgements.  This changed   9/13/97
                  xx  the break between pages xix and xx, so I had to
                 248  update the index entries for "Nemeth, Evi",
                 250  "USENIX Association", and "Internet Engineering
                 256  Task Force, The".

 ! 9/ 7/97 apm    20  "<" preceding strdup's return type should be       9/13/97
                      omitted.  (I also moved the comment over to make
                      the example easier to read.)

   9/ 2/97 sdm   136  In two comments on this page, "postpones" has an   9/13/97
                      apostrophe that shouldn't be there.

 ! 9/13/97 apm   184  In Set<T>::remove, the call to find should         9/14/97
                      terminate with a semicolon, not a colon.

The following changes were made for the fourth printing of the book. These changes apply to your copy of Effective C++, Second Edition only if you have one of the first three printings.


    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
  11/13/97 rmw    xv  In line 1 of 4th paragraph, change "small reward   2/ 3/98
                      for" to "small reward to".

   9/25/97 sdm xviii  Bad break in "Item 5" in 5th line from bottom of   2/ 3/98
                 xix  page on page xviii.  Caused page break between 
                      xviii and xix to shift. 
                      
   2/ 3/98 sdm   xix  Updated list of people who reported bugs in        2/ 3/98
                  xx  earlier printings I fixed in this printing.

  12/ 4/97 sdm     3  On 11/14/97, the ISO and ANSI standardization      2/ 3/98
                   6  committees adopted what is all but certain to
                 224  become the official standard for C++, so all
                 225  references to "draft standard," "nascent
                 234  standard," "DIS," etc. should refer to to just
                 235  "the standard."
                 236

  11/18/97  vb     5  Division by 10.0 unnecessarily forces use of       2/ 2/98
                      floating point math.  Change to division by the
                      int 10 instead.

   9/25/97 sdm  5,13, Made minor cosmetic change in punctuation,         9/28/97
                  24, hyphenation, or wording.                           2/ 2/98
               40,51, 
               62,75,
               95,98,
              99,107,
             116,117,
             125,144,
             161,164,
             178,183,
             185,195,
             219,229,
             233
                       
  11/ 5/97 en    6,8, The default constructor for my String class 
           sdm 49,72, shouldn't give its parameter a default value of
               87,94, 0 (the null pointer), because the standard
              95,124  string type exhibits undefined behavior when it
                      receives a null pointer.  I modified my examples
                      to be more in accord with the standard string
                      type, which offers the following constructors:
                        string();                // default ctor
                        string(const char *);    // ctor from C string  

   2/ 2/98 sdm     7  Bad line break between "Item" and "22" at the      2/ 2/98
                      end of the second prose paragraph.  Fixed.

 ! 9/25/97 sdm   7,8, "string class" => "string type".  As Item 49       9/28/97
               55,65, explains, string is not a class.                   2/ 2/98
             126,144,
             145,146,
             227
 
   9/25/97 sdm     9  Missing space between "assignment" and "By" in     9/28/97
                      first prose paragraph.
                       
  12/18/97 mmr  13,14 Contrary to my assertion at the beginning of the   2/ 3/98
                      Item, the preprocessor IS part of the formal 
                      language standard.  Furthermore, some 
                      implementations DO put the names of macros in the 
                      symbol table and DO show their names in error 
                      messages.  I reworded things to make them true.

  12/31/97 sdm    26  The exception should be caught by reference        2/ 2/98
                  30  instead of by value.  This is for efficiency.  
                  32  The full story is in More Effective C++, Item 13.

 ! 9/25/97 dxs    31  Comments after last two statements in the code     9/27/97
                      example are incorrect.  The call to
                      X::set_new_handler sets the handler to the null
                      pointer, and the subsequent use of "new X" will
                      call *no* error-handling function if allocation
                      fails. 

  10/13/97  rh    32  Misspelling in last prose sentence:               10/27/97
                      "newHanderSupport" ==> "newHandlerSupport".

   9/25/97 sdm    34  Replaced "0" with "null" in prose where I          9/28/97
                  35  referred to a pointer's value.  This is to avoid
                      implying that the *value* of a null pointer is
                      zero.  (If the book makes sense, but this
                      paragraph doesn't, ignore this paragraph.)

 ! 9/25/97 sdm    38  At beginning of paragraph following second code    9/28/97
                      block: "By defining a function" => "By declaring
                      a function". 

   1/ 1/98 sdm 57,59, unsigned int ==> size_t                            2/ 2/98
               60,62,
               95,96

   9/25/97 sdm    58  In first Wacko constructor, changed type of s      9/28/97
                      from char* to const char*.

   9/25/97 sdm    66  Bad break in "Item 11" in 3rd prose paragraph.     2/ 3/98

  10/16/97  mt    73  In comment inside operator=, "copy old data" ==>  10/27/97
                      "copy rhs's value"

  12/12/97 th     86  On line 20, a space is missing between "call."     2/ 2/98
                      and "But".

  12/10/97 dm     88  "different ... than" ==> "different ... from".     2/ 3/98
           sdm   121   
                 162
                 169
                 170

   9/25/97 sdm    91  Cross reference to Item 1 in 2nd paragraph should  9/28/97
                      be to both Items 1 and 47.

 !10/15/97 sdm    91  The type of string literals is now const char[],   2/ 3/98
                 215  (which almost always decays to const char*), so 
                      any place using a string literal to initialize or 
                      assign to a char* is technically illegal (it's a
                      violation of const correctness).  In practice, I 
                      expect all compilers to accept such code on the 
                      grounds of C compatibility, but it's still wrong 
                      in the book.  I added a footnote to page 91
                      explaining the situation, and I modified the example
                      on page 215 to avoid running into the problem.

 !10/27/97 sdm    97  strlen returns a size_t, not an int.               2/ 2/98
 
   9/15/97 sdm   108  The avg functions should all return doubles.       9/27/97
                 
   9/20/97 sdm   114  Style of Inheritance diagrams isn't consistent     9/27/97
                 158  with those in More Effective C++ or with that 
                 172  shown on page 231.  All diagrams should use the
                 177  "class names inside ellipses" style of page 231.
                 198
                 200
                 205
                 209
                 
  10/15/97  gb   131  In 1st line of 1st new paragraph, I say that      10/27/97
                      verifyAddress is protected.  It's not, it's
                      private. I adjusted the text.

  12/22/97  th   144  "Nobel prize-winning" ==> "Nobel Prize-            2/ 2/98
                      winning".  (Note change in capitalization.)
                      
   9/29/97 sdm   149  In last prose paragraph on page, parenthesis       9/29/97
                      following "virtual constructors" is in wrong font.

   9/13/97 apm   163  In 4th para, "only two kinds of plane" => "only    9/27/97
                      two kinds of planes".
                 
  12/31/97  th   174  Wrong font for 's' in first use of "BankAccounts"  2/ 2/98
                      in 3rd line from bottom.

   9/27/97 sdm   177  Space preceding "cred-" at end of page is in       9/27/97
                      wrong font.
                 
  12/17/97 mgh   184  Remove extra closing paren at end of               2/ 2/98
                      Set<T>::member's implementation.

 !11/19/97  jh   186  Stack and GenericStack lack a copy constructor     2/ 3/98
                 191  and an assignment operator, a direct violation 
                      of Item 11!  I declared them private in both
                      cases and added an xref to Item 27 for each.

 !11/26/97  tk   187  Stack::empty should return (top == 0), not         2/ 2/98
                      (top != 0).
 
   9/25/97 sdm   194  In middle of last paragraph of Item 42, cross-     9/28/97        
                      reference should be to Item 43, not Item 44. 

   9/21/97 apm   203  Three times on this page in the paragraph          9/27/97
                      following the code, "name" => "theName".

 !11/24/97 sdm   215  To what string should nameValue refer if the       2/ 3/98
                      char* constructor is called?  I modified the 
                      example to eliminate the problem.  (See also 
                      comment above about pages 91 and 215.)

 !11/11/97  jg   227  The "basic_ostream<char>" that precedes the        2/ 2/98
                      "template<class charT" shouldn't be there.  The
                      correct declaration for basic_string is:
                        template<class charT,
                                 class traits = char_traits<charT>, 
                                 class Allocator = allocator<charT> >
                          class basic_string;
 
  12/14/97 sdm   230  In the discussion of the algorithms' performance   2/ 3/98
                      guarantees, I changed the example from sort to
                      stable_sort, as the latter has a slightly stronger
                      guarantee.

   2/ 3/98 sdm   234  ISO stands for "International Organization for     2/ 3/98
                      Standardization", not "International Standards 
                      Organization".  Who knew?

  10/25/97  kb 235-6  The example code should show f as virtual,         2/ 3/98
                      because it doesn't affect the example in any
                      way, and using nonvirtual functions
                      unnecessarily violates the guidance of Item 37.

  10/28/97 sdm   236  A better way to make Base's f visible in           2/ 3/98
                      Derived is to add the following using
                      declaration to Derived:  
                        using Base::f;

The following changes were made for the fifth printing of the book. These changes apply to your copy of Effective C++, Second Edition only if you have one of the first four printings.

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
   9/29/97 sdm  x-xx  Running header should have section title up        6/ 9/98
                      against the binding margin.  As things stand now,
                      it's inconsistent with the rest of the book and
                      with More Effective C++.

   8/ 4/97 ds   x,59  The title to Item 14 suggests it may be okay to    6/ 9/98
                      create base classes with no destructors at all.
                      I changed the Item title to "Make sure base 
                      classes have virtual destructors."

   6/13/98 sdm    xix Added Dave Smallberg to list of pre-publication    6/13/98
                      reviewers.
                     
   N/A     N/A xix,xx Updated list of bug reporters.                     6/11/98

 ! 4/ 8/98 atc    26  The assert macro checks its argument only if       6/12/98
                 240  NDEBUG is undefined.  Furthermore, it's poor
                 250  programming to use assertions to detect
                      conditions that might occur in production code.
                      Running out of memory is such a condition.
 
   2/ 7/98 dxg    42  In line 15, "big enough hold" ==> "big enough      6/ 8/98
                      to hold"

   2/ 7/98 dxg    48  Change first word on page from "is" to "are"       6/ 8/98

   6/20/98 sdm    60  At beginning of last paragraph:  "topic: when"     6/29/98
                      ==> "topic.  When"

   6/17/98 sdm    72  In third prose paragraph, "One of them is          6/29/98
                      efficiency." ==> "The lesser of them is
                      efficiency."

  10/10/97 sdm    78  Header shouldn't have an Item number in it.        6/ 8/98

   6/28/98 sdm    91  The footnote I added on 2/3/98 isn't quite         6/29/98
                      correct.  It's true that the type of a string
                      literal is now const char[].  However, the
                      standard includes a loophole that allows char*
                      variables to be initialized with string literals
                      anyway, even though it's not const correct.  The
                      practice is deprecated, but, contraray to what I
                      said in the footnote, it's not illegal.  I
                      modifed the footnote.

   2/ 7/98 dxg    95  The String constructor should initialize           6/ 8/98
                      lengthIsValid to false, not 0.

   7/11/97 das Item 27 Note that the advice of this Item applies to all  6/13/98
                      compiler-generated functions, not just
                      operator=.  It's particularly common for both the
                      assignment operator and the copy constructor to
                      be explicitly disallowed.  I added a new paragraph
                      to the end of the Item (on p. 117).

   2/ 4/98 sdm 132-3  Space between "step" and "3" should be             6/ 8/98
                      non-breaking.

 ! 4/ 2/98 sdm   145  It turns out that the standardization committee    6/ 8/98
  12/13/99 sdm   146  has, with only a few exceptions (notably explicit
                 227  specializations for templates instantiated with
                 228  user-defined types), forbidden programmers from 
                 247  declaring anything that's in namespace std.  The
                 248  implication is that you shouldn't use the mechanism 
                      I show on p. 228 to declare the string type.
                      Instead, you should simply #include <string>.
                      (Edits to page 228 eliminated mention of
                      <iosfwd>, hence the modifications to Index
                      pages 247-248.)
                
   4/ 8/98 atc   147  Move "of" from line declaring returnADate to line  6/12/98
                      declaring takeADate.  This make is less likely 
                      that the takeADate comment will be read on its
                      own.

   4/ 8/98 atc   159  Reworded last sentence on p. 159 (to improve       6/12/98
                 160  clarity) and moved that sentence to the top of
                      p. 160 (to more closely associate it with the 
                      bulleted paragraphs).

   2/10/98 dxg   160  In line 17, "relationship it is" ==>               6/ 8/98
                      "relationship is"

   2/10/98 dxg   163  The last word in line 1 should be "behind"         6/ 8/98
                      instead of "for".

 ! 2/10/98 dxg   173  Lines 9 and 11 state that the dynamic or static    6/ 8/98
                      type of pr is Rectangle or Shape, respectively,
                      but the correct types are Rectangle* and Shape*.
 
   2/10/98 dxg   184  In the 10th line from the bottom of the page,      6/ 8/98
                      "In code" ==> "In the code"

 !11/26/97  tk   193  Parameter to GenericStack::push should be of type  6/ 8/98
                      void*, not const void*.
 
   4/ 8/98 atc   198  Reworded first large prose paragraph to avoid      6/12/98
                      using "invariably" in a way that really means
                      "almost always".  

   3/24/98  bc   203  In the paragraph preceding the code, PersonInfo's  6/ 8/98
                      member function names are incorrect:  the "the"
                      prefix has been omitted.

   6/ 8/98 sdm   203  Bad line break in third line after code example.   6/ 8/98

  11/19/97  jh   217  In the enum solution, Jan is 0, Feb is 1, ... Dec  6/ 8/98
                      is 11.  In the class solution, Jan is 1, Feb is 2,
                      ... Dec is 12.  I modified the enum solution to
                      make the numbering match the class-based solution.
                      (It's more intuitive for January to be 1, not 0.)

  11/19/97  jh   218  There should be a way to convert Month objects     6/ 8/98
   1/22/98 mdr        into ints.  This would be convenient for
                      comparing Months, etc.

   1/22/98 mdr   218  The copy constructor for Month shouldn't be        6/ 8/98
                 219  private, as there's nothing unsafe about copying
                      an existing month.  Allowing copying also makes it
                      possible to define local Month objects with nice
                      names, e.g.,
                        Month April = Month::Apr();
                        ...
                      That eliminates the need for the "final point"
                      discussion on page 219.  As a result, I decided 
                      to remove the copy ctor declaration and let the
                      compiler generate the default (public) version.

  11/10/97 max   221  The text claims it's not possible to determine     6/ 9/98
                      if it's possible to determine the correct order of
                      initialization, but it also claims it's not
                      possible to determine the correct order.  This is 
                      contradictory.  Reword.

   4/ 8/98 atc   229  Append " -- as well as with built-in arrays!" to   6/12/98
                      the last sentence on the page.

  11/18/97  vb   233  In the end, the goal of "compatibility with        6/ 9/98
                      traditional tools and environments" was not fully
                      achieved, because some inlining and template
                      rules stretch traditional linkers beyond the 
                      breaking point.  
                      
  10/15/97 clf   239  Merge the index headings "Before 0" and "0-9"      6/ 7/98
                      into "Before A" for consistency with the index 
                      in More Effective C++.
                     
  12/31/97  th 239-56 Index entries for "Protocol classes", "ABC", and   6/10/98
                      "Body classes" are incomplete or inconsistent.
                      Fixing these errors caused lots of page breaks 
                      in the index to change, so I just decided to 
                      reprint the entire index.  I also took the 
                      opportunity to add Chris Van Wyk and Oleg Zabluda
                      to the index, as they'd been inadvertantly
                      omitted

The following changes were made for the sixth printing of the book. These changes apply to your copy of Effective C++, Second Edition only if you have one of the first five printings.

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
   9/15/98 jww xviii  "Angelika Langer and Klaus Kreft" ==>              2/ 8/99
                      "Klaus Kreft and Angelika Langer"

   9/15/98 jww xviii  "Prentice-Hall, 1978" ==> "Prentice-Hall,          2/ 8/99
                      initially published in 1978".  (A second edition 
                      was published in 1988.)

   2/ 8/99 sdm    xx  Added axt, jww, bs, and lf to the                  2/ 8/99
                      acknowledgements.

   8/19/98 axt 34,35  Replace "while (1)" with "while (true)".           2/ 8/99

  11/30/98 bs     47  Because Airplane::memPool is a non-local static    2/ 8/99
                  48  object, care must be taken to ensure that it's
                      initialized before it's used.  The discussion on
                      these pages should include a cross-reference to 
                      Item 47.

   8/19/98 axt    60  For consistency with the code shown on page 59,    2/ 8/99
                      the initialization of EnemyTank::numTanks should
                      be shown.

   8/19/98 axt    62  In last paragraph, "NamedArray" is incorrectly     2/ 8/99
                      broken across lines.

   8/19/98 axt    79  In 3rd paragraph on page, "On other hand" ==>      2/ 8/99
                      "On the other hand"

   8/19/98 axt   109  Add comma after "see" in "(see e.g., Item 12)".    2/ 8/99

   1/18/98 lf    112  According to the C++ standard, there is no such    2/ 8/99
                      thing as an "anonymous class".  Rather, there
                      are "unnamed classes".  Hence, "anonymous class"
                      ==> "unnamed class".

   8/19/98 axt   151  In last paragraph, "virtual pointer" ==>           2/ 8/99
                 152  "virtual table pointer".  This changed a page
                      break.

   8/19/98 axt   176  Remove reference to Smalltalk in last paragraph,   2/ 8/99
                 254  as I'm told this remark isn't appropriate for 
                      software development in that language.

   8/19/98 axt   203  "brace" ==> "square bracket"                       2/ 8/99

   2/ 8/99 sdm   203  Bad line break in "valueDelimOpen".                2/ 8/99

The following changes were made for the ninth printing of the book. These changes apply to your copy of Effective C++, Second Edition only if you have one of the first eight printings.

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
  12/18/99 sdm    12  I added a new paragraph pointing out that I        4/28/00
                      generally omit mention of the std namespace in
                      example code.  Thus, I refer to cout instead of
                      std::cout, etc.

  10/ 3/99 sdm   xvi  Add mention of my mailing list, which announces    4/28/00
                      each time the on-line errata list is updated.

 ! 3/ 3/99 gy      5  The minus sign ("-") that precedes a negative      4/28/00
                      number is not a digit, so the number of digits
                      should not be incremented when the negative
                      number is made positive.
 
   2/22/99 bm     19  In the book, I wrote, "Besides, <iostream>         4/28/00
                      is less to type than <iostream.h>.  For
                      many people, that's reason enough to prefer it."
                      However, bm notes this: "Then these people
                      forget that they have to use qualified names
                      (e.g. "std::cout") or using declarations which
                      require many more letters than the two letters
                      saved :-)" Smiley face, indeed.  I removed the 
                      sentences. 

  10/25/99  fk    39  Misaligned comment on 15th line from top of        4/28/00
                      page. 

   4/ 9/99  bp    45  Add to the definition of a memory pool that it     4/28/00
                      never grows larger than the maximum amount of
                      memory requested by its clients AT ANY GIVEN
                      TIME.

 ! 5/24/99  cp    60  The initialization of EnemyTank::numTargets        4/28/00
                      should be EnemyTank::numTanks.
 
   4/24/00  id    67  References to the variable x on this page should   4/28/00
                      be to z, because the last part of the chain of
                      assignments on page 64 involves z, not x.

   3/27/99 joh    81  In last line,  clarify that "the classes's         4/28/00
                      interface" means the interfaces of the classes
                      generated from the Array template.

 ! 3/28/99 joh   178  In first line, "redefined" ==> "defined".  The     4/28/00
                      function creditInterest isn't defined in
                      InterestBearingAccount.

 ! 2/19/99 mdr   218  Only the Month objects returned from Month's       4/28/00
                      static member functions are guaranteed to be
                      const.  Month objects created by users need not
                      be const, and they may be modified via
                      assignment.

 ! 1/21/99 sdm 225-6  Contrary to the second bullet on this page,        4/28/00
                      names introduced via standard C headers *are* in
                      namespace std.  Matt Austern explained the
                      reason for this in a posting to
                      comp.lang.c++.moderated on 1/18/00:

                        <cfoo> headers define symbols in namespace std
                        only, while the <foo.h> headers define them in
                        namespace std and then import them into the
                        global namespace as if by using-declarations.
                        This is described in section D.5, paragraph 2,
                        of the C++ standard.

                        It clearly wouldn't work for the <cfoo>
                        headers to define names in namespace std only
                        and for the <foo.h> headers to define names in
                        the global namespace only.  If we did it that
                        way then (for example) we'd get two different
                        ldiv_t types, one from <stdlib.h> and one from
                        <cstdlib>.  As is we've instead got a single
                        ldiv_t that can be referred to from two
                        different namespaces.  Because of Koenig
                        lookup, it makes a difference which one it was
                        originally defined in.

                      I reworded the bullets to state for each one 
                      what's in the global namespace, what's in std, 
                      and what's in both.
 
   2/15/99 sdm   231  In the diagram, the tail of the arrow attached     4/28/00
                      to "range_error" pokes into the ellipse.  It
                      shouldn't.

The following changes were made for the eleventh printing of the book. These changes apply to your copy of Effective C++, Second Edition only if you have one of the first ten printings.

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
   3/ 7/01 das   xix  "Dave Smallberg" ==> "David Smallberg"             9/10/01
                 254

 ! 8/25/00 pm     68  In operator=, "*ptr = *rhs.ptr;" ==>               9/10/01
                      "ptr = rhs.ptr;"  Modify the comment
                      accordingly. 
 
   1/19/00 ccr    90  In order to cache a running average, you need      9/10/01
                      two pieces of data:  the overall total and the
                      number of things being counted.  The text in the
                      book implies that only one data member is needed.

   8/15/00 cb    104  Eliminate the bulk of the first prose paragraph    9/10/01
                 105  on this page.  When I originally wrote the 
                      paragraph for the first edition of EC++, the
                      example involved string objects, not rational
                      numbers, and for strings, the situation was
                      different.  When I changed the class for the
                      example, I failed to recognize that the words no
                      longer made sense for the example.
                        To avoid too unbalanced a page, I moved the
                      break between pages 104 and 105.

   8/16/00 cb    124  At the end of the 2nd to last sentence on the      9/10/01
                      page, it would be helpful to xref Item 21's
                      explanation that the data pointed to by a pointer
                      in a const object is not automatically const.

 ! 2/10/00 ic    212  A class declaring no operator& function(s)         9/10/01
           cxh   213  does NOT have them implicitly declared.  Rather,
                 245  compilers use the built-in address-of operator
                 246  whenever "&" is applied to an object of that
                      type.  This behavior, in turn, is technically
                      not an application of a global operator&
                      function.  Rather, it is a use of a built-in
                      operator.
                        I eliminated mention of operator& as an 
                      automatically generated function and adjusted the
                      index to eliminate entries for the removed 
                      material. I also changed the definition of
                      e1 from const Empty to Empty, because I no 
                      longer needed a const object to make my point.
 
   7/ 3/00 ms    216  Saying that Lisp is "almost always interpreted"    9/10/01
                      is inaccurate.  Change "these languages are
                      almost always interpreted" to "these languages 
                      typically include interpreted components".

 ! 4/ 8/01 hs    228  The Standardization Committee has now ruled that   9/10/01
                      library implementers must declare string as
                      defined in the Standard, so my comment about
                      their being allowed to add extra parameters is
                      incorrect.  However, the Standard continues
                      to forbid you from declaring string yourself.
                      The advice in this Item stands (#include
                      <string> instead of trying to declare the string
                      type yourself), but the rationale for that
                      advice is no longer valid.

The following changes were made for the twelfth printing of the book. These changes apply to your copy of Effective C++, Second Edition only if you have one of the first eleven printings.

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
   9/21/01 pxm     6  I should clarify that operator+ is assumed to be   8/26/02
                      a friend of String, hence has access to 
                      String::data.

   8/26/02 sdm    24  Bad line break: "ty-pedefs"                        8/26/02

   7/ 6/01 ga     51  Regarding the para after the first code fragment,  8/26/02
                      the place pointed to by a and c will actually be
                      deleted three times, because it will already
                      have been deleted when b went out of scope.

   7/ 6/01 ga     64  At end of 2nd para, "a twist" ==>                  8/26/02
                      "an aspect to it".  This avoids repeating the
                      word "twist," which was used on the previous 
                      page.

   7/ 6/01 ga     64  "freestanding functions" ==> "actual               8/26/02
                      functions in the object code"

 ! 1/22/02 fb    107  The information on this page is correct for        8/26/02
                      integral types, but for floating point types,
                      it's not.  For floating point types, the data on
                      the "minimum possible value" in <limits>,
                      <limits.h>, and <climits> is for the minimum
                      representable positive number, e.g., 
                      both DBL_MIN and numeric_limits<double>::min()
                      are greater than zero.  For a floating point
                      type FPT, the minimum representable value is 
                      typically -numeric_limits<FPT>::max(), though 
                      the Standard does not guarantee this.
                        I reworded the discussion to be true and
                      added a footnote to explain the meaning of 
                      numeric_limits<T>::min when T is a floating
                      point type.

   7/ 6/01 ga    182  Another common synonym for layering is             8/26/02
                      "aggregation". 

  10/17/01 js    202  In the first para, the phrase "begs the question"  8/26/02
                      is improperly used.  Reword.

   7/ 6/01 ga    203  Twice on page, "PersonInfo::name" ==>              8/26/02
                      "PersonInfo::theName".

 ! 7/ 6/01 ga    226  In 2nd to last para, "string" isn't a template,    2/26/02
                      it's a typedef for a template instantiation.

The following changes were made for the fifteenth printing of the book. These changes apply to your copy of Effective C++, Second Edition only if you have one of the first fourteen printings.

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
  10/12/02 bj     12  Clarify that the "ISO/ANSI sanctified version     10/ 8/03
                      of C" I refer to in the book is C89 or later
                      (i.e., C89 or C99).

   4/10/03 wk     77  The final bullet point on the page is misleading. 10/ 8/03
                      C++ imposes constraints on how copy constructors
                      behave, so rather than writing that a copy 
                      constructor defines what it means to pass
                      by value, I should say that it defines how
                      an object is passed by value.  (But see 
                      wk's 6/17/03 comment below regarding
                      pathological cases where the copy constructor is
                      bypassed in favor of a "copying constructor.")

  10/20/02 kk    125  In final sentence of 2nd-to-last paragraph,       10/ 8/03
                      clarify that callers must use the array form of 
                      delete.

  10/12/02 bj    135  In first para, note that the "C philosophy that   10/ 8/03
                      variables should be defined at the beginning of 
                      a block" is for C prior to C99.

 !10/12/02 bj Item 41 The first design problem includes the ability to  10/ 8/03
                      create "stacks of stacks of strings," but the 
                      given solution has a private copy constructor,
                      making it impossible to create a Stack of Stacks.
                      Rather than modify the code, I revised the 
                      spec :-)

   8/13/03 mc    222  There is more to the Singleton pattern than I     10/ 8/03
                      describe in this Item.  In particular, I make
                      no mention of how to limit instantiation of a
                      singleton class to one.  As mc notes,
                      "You can't spell 'singleton' without spelling
                      'single.'"  I added a clarifying footnote.

The following changes were made for the sixteenth printing of the book. These changes apply to your copy of Effective C++, Second Edition only if you have one of the first fifteen printings.

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
   4/ 4/04 sdm  xiii  Bad line break in URL in footnote.                 6/ 7/04
  
   5/20/04 md    107  At end of 3rd para, "SHRT" is in wrong font.       6/ 7/04

   6/ 1/04 md    203  In last line, "theName" ==> "name".                6/ 7/04

   6/ 7/04 sdm   203  Bad line break in 2nd-to-last para in              6/ 7/04
                      "valueDelimOpen". 

   6/ 2/04 md    218  In 2nd to last line, "accidently" ==>              6/ 7/04
                      "accidentally".  Both spellings are correct but
                      I use the "ally" form everywhere else in the
                      book, so I should use it here, too.

   6/30/04 mr    229  At bottom of page, "!." ==> "!"                    6/30/04

   1/19/04 jyt   231  Arrow tail protrudes slightly into the oval        6/ 7/04
                      surrounding "overflow_error".

The following changes were made for the seventeenth printing of the book. These changes apply to your copy of Effective C++, Second Edition only if you have one of the first sixteen printings.

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
   5/16/04 md     77  "an intuitive semantics" ==> "intuitive            8/15/04
                      semantics"

   5/16/04 md     83  "minimalness" ==> "minimality"                     8/15/04
                 244

   7/ 7/04 al    205  valueDelimOpen and valueDelimClose should be       8/15/04
                      declared private in MyPerson, because clients
                      should not be able to call them.  They're just an
                      implementation detail of the class.

What follows are interesting comments about the material in Effective C++, Second Edition, but note that the book has now been superceded by Effective C++, Third Edition.

    DATE
  REPORTED WHO  PAGES  WHAT
  -------- --- ------- ----------------------------------------------------------
  12/18/97  th      xv Sir James Murray (first editor of the Oxford English
                       Dictionary) predates Knuth in offering a reward to
                       readers who bring errors to his attention.  And
                       Murray was dealing with thousands of pages of fine
                       print, quotations from Old and Middle English, as
                       well as numerous examples in foreign languages (some
                       in non-Roman alphabets).

   6/27/05 bxs     5   Line 2 ("number = -number;") won't work as expected on
                       2s complement machines if number is the smallest
                       representable value.  (In general, no arithmetic
                       operations will behave as mathematically expected when
                       variable values are outside the representable range.)

  11/13/03 dfc     9,  The code for the String class isn't exception safe.  When
                  73   I wrote the book, I frankly wasn't concerned about
                       exception safety, but I should have been.  When I write
                       the third edition of the book, I'll be careful to pay
                       attention to exception safety throughout.

   3/25/98 sdm  Item 1 Many people have expressed concern that if ASPECT_RATIO
                       is defined as a const, it will occupy memory, whereas
                       if it's a macro, it won't.  This need not be true.  I'd
                       expect any decent compiler to replace use of ASPECT_RATIO
                       with its value and to optimize its storage out of
                       existence.  In other words, with a good compiler, use
                       of a const is as space-efficient as use of a macro.

   7/ 3/01 jcj  Item 1 Regarding the argument that using a macro to represent a
                       floating point literal (such as on page 13) is more space-
                       efficient than using a const object, jcj writes:
 
                         The [const] form is at least as efficient as the #define
                         because when the preprocessor replaces ASPECT_RATIO with
                         1.653 in one's source code, that value must be stored
                         somewhere in the binary machine code.  Clearly the fact
                         that one has a floating-point literal, in addition to the
                         fact that I can think of no machines that have any
                         instructions that take floating-point immediates, it is
                         quite obvious that 99.9% of the time 1.653 will occupy
                         some typically 64-bit space in memory that will be loaded
                         and used just like a constant would.  In fact, when you
                         realize that the preprocessor and the compiler may not be
                         very tightly coupled, the #define form would define a
                         floating point literal at every point ASPECT_RATIO is
                         used, where the const form would only have one instance in
                         memory no matter how many uses there are.  When you have
                         consts that refer to types that may be allowed as
                         immediates in the instruction set of the compiler, it is
                         possible that the #define could be faster if the compiler
                         did not optimize in the same way, but in general I'd be
                         more worried about 50 floating-point literals peppered
                         throughout my code than 1 constant used 50 times.

   8/ 8/00 cb       15 Observes cb:
 
                         It appears that the Microsoft Visual C++ 6.0 SP3 compiler
                         requires the "enum hack" to work.  Interesting, since it
                         is stated that "Unless you're dealing with compilers of
                         primarily historical interest (i.e., those written before
                         1995), you shouldn't have to use the enum hack."
 
                       It appears that Visual C++ 6 was released in mid-1998.
                       Sigh. 

   1/ 8/02  yy      15 The "enum hack" may be better than static const objects in
                       two cases.  The first is when compilers fail to optimize
                       away the storage for the const object; enums occupy no
                       storage.  The second is if compilers generate code to
                       initialize the value of the const object at runtime instead
                       of at load time.  Because enums occupy no storage, there is
                       no storage to initialize.

  10/11/97 ncm      15 Enumerants are in upper case, but this makes them 
                    81 supceptible to replacement via macros.  (On the other hand,
                   171 if an enumerant is macro-replaced by a constant, the
                       enum definition itself should not compile.)

   7/11/97 das  Item 4 "I've never bought the "Look how dangerous it is to 
                       comment out code with /* */" justification for // comments,
                       since the right way to do it in C is #if 0 ... #endif.  My
                       justification is that if you look at the middle of a large
                       block of code commented out with #if 0 ... #endif (or /*
                       ... */ for that matter), it isn't obvious that the code is
                       commented out.  It's much more apparent when every
                       commented out line starts with //."

   8/19/98 axt  Item 4 You could mention the "#if 0, #endif" method of commenting
                       out code. This method is convenient for commenting out
                       chunks of code and, contrary to /* ... */, nesting is no
                       problem.

   6/20/01 cbs Items   cbs points out that the code in Item 30 isn't thread safe,
           sdm 7,8,10  but the problem exists in Items 8 and 10, too.  In fact, I
                       fail to consider thread-safety throughout the book,
                       something I can argue is excusable only because C++ itself
                       fails to consider threading issues.  You'll see other
                       comments on how threading interact with my advice in
                       various places in this errata list.  If I ever write a
                       third edition, I'll be sure to take threading issues into
                       account.

   7/ 6/01 ga  Items   operator new should include exception specs.  This  would 
                 7-8   make parts of these Items easier to follow.  On the other
                       hand, if I use exception specs here, I'd need to use them
                       in Items 9-10, too, and also on operator delete and
                       possibly elsewhere.  The book currently uses almost no
                       exception specs, and perhaps it is more consistent that
                       way.

   1/19/98 mdr      32 Inheritance from NewHandlerSupport should really be
                       private, because the lack of a virtual destructor in
                       NewHandlerSupport means that deletion of an X object via a
                       NewHandlerSupport<X>* pointer yields undefined behavior.
                       The details are covered in my April 1998 article in the 
                       C/C++ Users Journal, but they're complicated, and I frankly
                       don't know of a graceful way to integrate them into the 
                       existing text of the book.

   6/24/98 sdm      33 "nothrow" new turns out to be less useful than it initially
                       appears.  Consider this statement:
 
                         Widget *pw = new (nothrow) Widget;
 
                       As Item 5 points out, two things happen here.  First, the
                       nothrow form of operator new is invoked to get enough
                       memory for a Widget object.  Second, a Widget constructor
                       is invoked.  Use of nothrow new guarantees that no
                       exception will be thrown if operator new is unable to
                       allocate the memory for the Widget, but if operator new
                       succeeds, the Widget constructor will be invoked, and
                       "nothrow" has no impact on that at all.  In particular, the
                       constructor is free to exit via an exception.
                         This means that the statement above may yield an
                       exception.  If it does, the exception could not have come
                       from the invocation of operator new that preceded the call
                       to the Widget constructor.  It may, however, have come from
                       an invocation of a non-nothrow new used inside the Widget
                       constructor.
                         Bottom line: don't read "new (nothrow) Widget" as
                       promosing that no exception will be thrown, because that's
                       not what it means.

   4/ 5/99 sdm   38-39 From the discussion on page 236, one might think that a
                       using declaration could be used to avoid hiding the
                       "normal" form of new, i.e., you might think this would
                       solve the problem:
 
                         class X {
                         public:
                           using ::operator new;
                           ...
                         };
  
                       Alas, this won't work, because using declarations within
                       classes can bring only members of base classes into scope.
                       Since ::operator new isn't a member of a base class of X,
                       there's no way to employ a using declaration to avoid
                       hiding the "normal" form of new.

  10/ 6/06 txz     42  The call to ::operator new to "allocate a block of
                       memory big enough to hold BLOCK_SIZE Airplane objects"
                       should be to ::operator new[] instead, because we're
                       really allocating memory for an array here.  

   6/17/98 sdm   46-47 Unlike the Pool class sketched on these pages, an
                       industrial-strength Pool class would adhere to the
                       conventions of allocators in the standard C++ library.  You
                       can find a description of such conventions, as well as an
                       example showing how to give a Pool-like class a conforming
                       interface, in section 19.4 of the 3rd edition of Bjarne
                       Stroustrup's The C++ Programming Language.
                    
  11/25/97 kga Item 11 Only non-template constructors and assignment operators
                       prevent the generation of the default versions of these
                       functions.  Hence, classes with member templates for
                       constructors and assignment operators must still explicitly
                       declare a copy constructor and an assignment operator for
                       classes with pointers.  (If this makes no sense to you,
                       don't worry about it.)

   6/ 9/98 sdm Item 11 It has been suggested that I add a destuctor to the list of
                       functions that should be declared if a class dynamically
                       allocates memory, but I've decided not to.  If a destructor
                       is omitted, the usual effect is a memory leak (see Item 6).
                       However, if a copy constructor or an assignment operator is
                       omitted, the usual result is undefined program behavior.
                       These are qualitatively different situations.  Furthermore,
                       it often makes sense to declare, but not define, a copy
                       constructor and/or assignment operator.  This is never
                       valid for a destructor.  As Item 14 explains, a destructor
                       must always be defined if it's declared.
                     
  12/10/03 sn  Item 12 As Item 11 explains, bitwise copy is virtually always
                       incorrect for pointer data members, but it is often
                       simpler to "do the right thing" via assignment vis-a-vis
                       initialization for pointer data members.  So it may make
                       sense to assign to pointer data members instead of
                       initializing them.

   9/19/98 axm   55-57 Another approach is:
                       
                         class DataMbrs {
                         friend class ManyDataMbrs;
                         private:
                            DataMbrs(): a(1), b(1), c(1) {}
                            int a, b, c;
                         };
                       
                         class ManyDataMbrs: private DataMbrs {
                         public:
                            ManyDataMbrs() { ... }
                            ManyDataMbrs(const ManyDataMbrs& x) { ... }
                         };
                       
                       In other words, move the common constructor
                       initialization list in ManyDataMbrs into a single
                       constructor of a private base class, using friendship
                       to make sure nobody except ManyDataMbrs has access to
                       the members of the base class.  Advantages of this
                       approach: it is more efficient for non built-in types
                       and users don't have to call init() inside each
                       constructor.

  12/28/04 mm      58  The code example is bad, because, as I point out in the
                       footnote on page 8, initializing a std::string with a
                       null pointer yields undefined behavior.

   6/ 2/00 bk  Item 14 Some base classes are designed for public derivation, but
                       not for polymorphic use.  This is the case for
                       unary_function and binary_function in the standard library.
                       For such base classes, a protected nonvirtual destructor
                       may be more appropriate than a virtual destructor.

   1/ 5/99 ivr      66 It turns out that "(i1 = i2) = i3;" yields undefined
                       results when i1, i2, and i3 are ints, because i1 is
                       modified more than once without an intervening sequence
                       point.  This is not a problem for user-defined types,
                       because for such types, the above is equivalent to
 
                         (i1.operator=(i2)).operator=(i3);
 
                       and that's fine, because there's a sequence point
                       before and after each function call.
 
                       The question then arises: why is "i1 = i2 = i3;"
                       allowed when i1, i2, and i3 are ints?  A definitive
                       answer was provided by Andrew Koenig in a 
                       1/6/00 posting to comp.std.c++.

   6/14/02  es      66 Regarding my comment after the second code example that I
                       know of no practical use for things like (w1 = w2) = w3, 
                       es offers the following, which do strike me as reasonable:
 
                         string str1;
                         string str2("123456");
                           
                         (str1 =str2).replace(2, 2, "abcdefgh");
                         (str1 +=str2).replace(5, 2, "XYZ");

   6/ 5/01 sdm      67 In the prose following the third code example, it's not
                       technically true that the temporary is const.  Rather, the
                       temporary is an rvalue, and C++ forbids binding references
                       to rvalues unless they are references to const.  This is
                       not a bug in the book.  Rather, it is a deliberate attempt
                       to spare you from having to know about rvalues, because
                       they're more confusing than helpful, especially if you know
                       the rules for rvalues in C.  Setting aside technicalities,
                       the information on this page is accurate in its
                       essentials. 

   5/30/08 lxz      68 lxz writes:

                         On the 2nd to last line of code, it says, "*ptr =
                         *rhs.ptr;".  The errata list (above) says to change this 
                         to "ptr = rhs.ptr". But doesn't this introduce a memory 
                         leak?  What happens to the memory that was being
                         pointed to by ptr?  (I believe this issue is discussed
                         on page 73.)  Also, now you've got two pointers
                         pointing to the same object.

                         I think you have to do something this:

                           delete ptr;  // or should it be delete []ptr; ?

                           ptr = new (T*)(char [sizeof(*rhs.ptr)/sizeof(char)]);

                           *ptr = *rhs.ptr;

                         Hopefully, T's overloaded assignment operator won't
                         leave dangling pointers, etc.  Does that sound right?

                       It does.  These days my preferred solution would be to
                       use some kind of smart pointer instead of a raw pointer
                       (i.e., change the type of ptr from T* to
                       SomeKindOfSmartPtr<T>), because that would shift the
                       problems onto the smart pointer class.

   6/ 4/02  ai      72 ai writes:  "In your description about programmers writing
                       "a = a;" you say it's silly, but point out that it could be
                       caused by reference aliasing.  I've also noticed it done by
                       programmers new to C++ to get rid of the "usused
                       variable/parameter" warning."

   1/19/04 jyt Items   There are several example base classes in the book that
               16,     declare nonvirtual destructors or that declare no 
               22,     destructor at all, a violation of Item 14.
               26,   
               40,43,
               49,50

   2/17/03 dyx Items   "Our programming guidelines now recommend implementing
               16-17   assignment operators like this:
 
                         T const& T::operator=( T other )
                         {
                           swap( other ); // non-throwing operation
                           return *this;	
                         }
 
                       My reply:

                         This is fine (except for the const return type :-}), as
                         long as you make clear that this approach may be
                         needlessly expensive.  For example, if all your data
                         members are of built in types, their assignments can't
                         throw, so doing swaps instead of assignments just burns
                         cycles needlessly.  For large objects, you're talking
                         about duplicating an object's contents on the heap in
                         order to be able to perform the non-throwing swap.
                         There's nothing wrong with that, but my experience has
                         been that people advocating this approach to implementing
                         operator= often overlook the cost that it incurs.  It's
                         exception safe, but it's often not cheap.

   6/17/03 wk     77   There are pathological cases where pass by value is
                       accomplished by instantiations of "copying constructors"
                       rather than by the class' copy constructor.  For details,
                       consult the comp.lang.c++.moderated thread on the topic.

   1/ 1/98 sdm Item 18 Anybody developing a real Array template (or a template for
                       any other kind of container) should make sure the final
                       product adheres to the conventions of the Standard Template
                       Library (see page 232).

   6/22/01 sdm Item 19 The bulleted summary at the end of this Item no longer
                       reflects my full thinking on this topic.  For an updated
                       version of the summary as well as an explanation of how and
                       why things changed, please read my February 2000 article,
                       "How Non-Member Functions Improve Encapsulation."
 
   2/19/01 sdm Item 19 When templates enter the picture, things become more
                       complicated.  Compilers must not only perform type
                       conversions on actual parameters, they must also perform
                       template type deduction to determine the types of formal
                       parameters.  The end result is that templates for functions
                       like operator+ should still be non-members, but they need
                       to be defined as friends inside the class they work with in
                       order to be instantiated correctly. 

  12/30/02 ma  Item 19 It's true that virtual functions must be members, but one
                       can get virtual-acting behavior by having a non-virtual
                       function (possibly a non-member) call a virtual function.
                       This can be especially useful for functions like operator<<,
                       which must be non-members but can be made to act virtual by
                       internally calling a virtual function, e.g., one named
                       "print" or "write".

   2/17/03 dys Item 19 Regarding the last bullet on page 88, dys writes:  

                        The same rule should be used for other operators that
                        require a different class as a left-hand operand. For
                        example, CORBA uses "Any <<= Type", and for all classes
                        besides Any, operator<<=(T) is a non-member.  I propose
                        the following change to your algorithm. Instead of
                      
                          else if (f is operator>> or operator<<)
                      
                        write
                      
                          else if (f is an operator and needs another class as
                                   its left-hand operand)
                    
  11/ 3/97 dqs Item 20 "When writing code for parallel execution in a
                       multi-threaded environment it is important to know what
                       code can modify what areas of memory.
  
                       If member data of a class is made public, a critical
                       section of code for that area of memory could be anywhere.
                       As the creator of the class I have no way to ensure that
                       the memory is referenced only under the appropriate access
                       controls.  On the other hand, if the member data is made
                       private, I know that all of the critical sections are
                       within the methods of the class.  If I ensure that these
                       methods only reference the member data under the
                       appropriate access controls then I can ensure the class is
                       safe to use in a multi-threaded environment.  This also
                       holds for returning pointers or references to private data.
                       Returning such a value allows someone to reference my
                       object's memory without using the appropriate access
                       controls."

   9/17/00 ch Item 20  Notes ch:
 
                         Objects are state machines. An Object would lose control
                         of its own states if you allow public data members. This
                         makes it for instance impossible to implement a typical
                         Observer Pattern in an object oriented way. The problems
                         get really nasty for objects with public data members
                         when living in a multithreaded environment ....
 
   9/ 6/00 bxp Item 21 bxp makes the following quite legitimate observation:
  
                         [Item 21 has] a long discussion on const functions,
                         returning const object values, etc, but a very important
                         approach is missing: const locals. Any local variable you
                         mean not to change later on should be declared const.  It
                         is highly documenting, helps the compiler, and helps to
                         avoid bugs too.

   6/29/05 bxs Item 21 One way to remember what const refers to when pointers are
                       involved is to read the declarations right to left: 

                         char *p              // ptr to char
                         const char *p        // ptr to char that is const
                         char const *p        // ptr to constant char
                         char *const p        // constant ptr to char
                         const char * const p // constant ptr to char that is const
                         char const * const p // constant ptr to constant char

   4/16/99 sdm   93    Several people have asked why the const version of
                       String::operator[] returns a const char& instead of a
                       char. It's because returning a char would prevent users
                       from taking the address of the result.  In other words, if
                       the const operator[] returned a char, this would be
                       illegal,
 
                         const String s;
                         ...
                         const char *p = &s[5];  // error -- can't take address
                                                 // of a built-in type returned
                                                 // by value 
 
                       but this would be legal:
 
                         String s;
                         ...
                         char *p = &s[5];        // fine -- taking the address of
                                                 // the char referred to by
                                                 // operator[]'s return value 
  
                       I don't like that kind of inconsistency.  Also, return by
                       reference generalizes much better to other types.

  12/21/97 wbr Item 22 Another reason to prefer pass-by-reference is that it works
                       even when the copy constructor is not public. Item 27
                       gives an example of when this might be the case.

   9/10/01 lz     97   If you are using a library with a const-incorrect function
                       prototype such as that for strlen on this page, there is a
                       solution better than using a cast at every point in the
                       program where you call the incorrectly-declared function:
                       write a wrapper function to perform the cast, then call
                       the wrapper.  In the example on this page, the wrapper
                       function would look like this:
                         inline strlen(const char *s)
                         { return strlen(const_cast<char*>(s); }

   6/11/00 tm     99   In general, it's dangerous for a function to return a
   9/18/03 ss          reference to a parameter passed by reference-to-const,
                       because the parameter may have been bound to a temporary
                       object that will usually be destroyed at the end of
                       the call. For details, consult FAQ 32.08 of C++ Faqs by
                       Cline, Lomow, and Girou.

   2/27/01 ph Item 23  Once you've resigned yourself to returning a new object
                       from functions like operator*, you'll naturally look for
                       ways to make that as cheap as possible.  One way to do that
                       is to return a pointer posing as an object.  
                         The following comment was sent regarding Item 20 of 
                       More Effective C++, but it's relevant to Item 23 of 
                       Effective C++, too: 
 
                         We faced the problem of getting large float and int
                         arrays from a database. The dimension of the array
                         depended on the time interval passed as an argument to
                         the reading method. Clearly, we had to return an object,
                         and we couldn't rely upon return value optimization
                         [which is the subject of MEC++ Item 20].
                       
                         Our solution was to return an auto_ptr<Array<T> > instead
                         of an Array<T>. This way, we had the advantage of
                         returning something as light as a pointer without the
                         problem of potential memory leaks. The only drawback was
                         a slightly heavier syntax but it was worth it.
                       
                         I don't think this is a solution for the method operator*
                         that you used in item 20 but many other methods that have
                         to return large objects may benefit from it.

   7/ 1/03 sv    108   The last sentence says you must use overloading, but if
                       you are willing to change the API, you have other choices,
                       e.g., you could pass a vector of values.

  11/23/97 sdm   111-2 With the conventional definition of NULL as 0, it's
                       legal to write "if (NULL) ... ".  This isn't legal with my
                       NULL, because it's ambiguous how to convert from NULL to
                       bool.  I'm not going to lose sleep over this, because it's
                       hard to imagine that NULL is used as a condition in much
                       code.

    7/10/00 sdm  111-2 Const objects of non-static storage duration that lack
    6/26/08 lfr        default constructors must be explicitly initialized,
                       even if they contain no data members.  As a result, in
                       the remote chance that a NULL object is declared with
                       non-static storage duration (e.g., a local object), the
                       code on these pages should not compile.  Because any
                       definition of a NULL object is likely to be at global or
                       file scope (hence of static storage duration), it's
                       unlikely this would be a problem in practice.

   1/14/98 sdm Item 29 Item 29 subsumes Item 30.
               Item 30
                      
   9/26/02 mh      127 It might be better if someFamousAuthor returned a 
                       const String instead of just a String.  This would be
                       consistent with the advice of Item 21.  However, the
                       decision as to whether to declare the return value const
                       depends on how callers are likely to use the return
                       value.  Some functions return values that clients may well
                       want to modify.
                     
   6/15/02 sdm Item 33 Randy Meyers (no relation) has a nice article on inlining 
                       in C99, including an explanation of how the C99 rules differ 
                       from those in C++, in the July 2002 issue of the
                       C/C++ Users Journal.

   7/11/97 das     137 "I don't buy the pathological paging behavior argument,
                       since you still have locality of references.  I recall an
                       IEEE Transactions on Software Enginering paper about seven
                       years ago that measured the effects of inlining code bloat
                       in an effort to verify or refute some folk wisdom about
                       thrashing.  I think they said it's not a problem."
                     
   8/26/02 sdm     149 What I call a "Protocol class" is now almost universally
                       known (especially outside the C++ community) as an
                       Interface.  Many languages (notably  Java and C#)
                       provide language support for them.

   5/19/03 sdm Item 34 Because it's not possible to declare nested classes
                       without defining the class in which they are nested,
                       nested classes can lead to unnecessary compilation
                       dependencies.  An alternative design is to unnest the
                       class and include both classes in the same namespace.
                       However, this is viable only when the nested class is
                       public, because namespaces offer no encapsulation.

  12/ 6/99 mp  Item 34 The use of a factory function to construct a class implies
                       that the "new" happens off the same heap, which is a bad
                       assumption when dealing with libraries (especially dynamic
                       link libraries).  This is why I prefer your first
                       recommendation of using the private implementation:
                     
                         class PersonImpl;
                         class Person {
                         ...
                         private:
                           PersonImpl *imp;
                         };
                     
                       While you do pay a redirection penalty when accessing
                       implementation data in the class, the following more
                       natural code works regardless of the heap situation:
                     
                         Person *pp = new Person(... );
                         ...
                         delete ppl;
                     
                       AND it allows stack-based or compiler-generated
                       constructors (especially useful with operators).  Basically
                       the "imp" pointer is allocated off the calling scope's
                       heap, and the PersonImpl data is allocated off the
                       library's heap.

   7/11/97 das Item 35 "A related true story:  The professor for the University
                       of Utah's general intro astronomy class, at the first
                       opportunity in the term, tells his class "I'm going to
                       tell you a question that will be on the final, and I'll
                       tell you the correct answer to that question. The question
                       is `Can the Moon be seen during the day?' and the answer
                       is yes.  Now, everyone come outside."  He takes his class
                       outside, points up to the Moon, and says "See, it's
                       daytime, and there's the Moon."  On the final, he asks
                       "Can the Moon be seen during the day?" Usually about a
                       third of the class answers no."

  10/13/02 ya Item 36  ya writes:  "Nonvirtual functions may call other functions
                       which are virtual. In that case, derived classes are indeed
                       presented with mandadory implementation, but only in the
                       highest, close-to-the-surface level. By overriding virtual
                       functions, the overall behavior of the nonvirtual function
                       can change in derived classes. Such usage of nonvirtuals is
                       very useful and is the basis for the 'template method'
                       design pattern."
                         This is true, but it's important to note that the
                       externally observable behavior of any function is defined
                       by its specification (i.e., it's interface), not by its
                       implementation.  A nonvirtual implemented using template
                       method may behave differently for different derived
                       classes, but its behavior is still bounded by its
                       specification.  Callers don't care whether the function is
                       virtual or nonvirtual.  All they care about is that the
                       function they call exhibits the behavior its specification
                       promises.
                         For implementers of derived classes, it's a different
                       story.  They care very much about whether a base class
                       function is virtual or nonvirtual, because that affects
                       what they are allowed to vary.  In Item 36, my remarks are
                       focused on the relationship between authors of base and
                       derived classes, not on the relationship between authors of
                       a class and clients of that class.

   6/11/03 sf Item 38  A drawback to the advice in this Item is that callers
                       going through the derived class interface must specify all
                       parameter values; the default parameter values apply only
                       via the base class interface.  An alternative design is to
                       respecify the (same) default value in each derived class,
                       but then if the default is changed in the base class, all
                       derived classes must be updated with the new value, too.

   7/21/04 am  179-180 Another way to deal with the need to downcast if you can't
                       redefine allAccounts or BankAccount is to declare something
                       like NewBankAccount as a sibling class to SavingsAccount
                       and CheckingAccount, then adopt a policy of deriving new
                       classes only from NewBankAccount.  You'll still have to
                       downcast from BankAccount to Savings-, Checking-, or
                       NewBankAccount, but once you're in NewBankAcount, you can
                       use a virtual creditInterest.

   8/30/15 lfr     184 In Set<T>::remove, "list<T>::iterator it" ==>
                       "typename list<T>::iterator it".

  12/18/97 rhs     190 In the second-to-last paragraph, I summarize when to use
                       layering and when to use private inheritance, but that
                       summary doesn't tell the whole story.  Sometimes private
                       inheritance is preferable to layering, even though neither
                       protected members nor virtual functions are involved.  
                       Nathan Myers, for example, has described why it can be
                       better to inherit from an empty class than to be layered on
                       top of an empty object.  For details, see 
                       Nathan's article on the topic.
 
  11/12/99 dh      190 In the second-to-last paragraph, I fail to explain why I
  11/15/99 jxg         prefer layering to private inheritance.  My reason is
                       simple (I think layering is a lot easier to understand),
                       but jxg posted additional reasons in a posting to
                       comp.lang.c++.moderated: 
  
                         - [Private inheritance] pollutes the class's scope with
                           names. The name of the private base plus the names of
                           its members are injected into the derived class.  They
                           may hide global names there, yielding unexpected 'XXX
                           not accessible' compilation errors (particularly in
                           classes derived from ours). One example: in derived
                           classes you cannot refer to the base class (supposedly
                           an implementation detail subject to change) with an
                           unqualified-id anymore. Global functions and objects
                           may be hidden (and reported as inaccessible) even by
                           private members of the private base.  Unexpected
                           ambiguities with other bases may arise. So changing the
                           implementation might break client code.
                      
                         - Even more detrimental effects occur in the classic case
                           of using private inheritance: to override a virtual
                           function. If the private base contains virtual
                           functions they become part of our class's interface and
                           could be overridden by derived classes. This is often
                           not what was intended (we inherit _private_ly after
                           all). If feasible, I would effect such overrides by
                           containing a private nested class nowadays.

   8/13/03 mc Item 43  Slightly edited, mc writes: "You are not completely
                       fair in this Item.  The trick with auxillary classes is
                       needed in order to allow overloading of any
                       functionalities involved in the name clash, but the
                       clumsiness and the lack of virtual behavior are not
                       valid arguments. Explicit qualification is clumsy, but
                       so is explicit upcasting of pointers (it takes more
                       than one line, compare upper page 196 with middle page
                       197). So clumsiness is not the argument here. Moreover,
                       calling pls->draw(); on page 197 would still be an
                       error just as on page 196, so don't bad-mouth the first
                       approach on that account. Reversely, applying the
                       pointer upcast trick on page 196 instead would conserve
                       the virtual behavior. So the only argument left is that
                       only one of the methods can be overloaded, the other
                       will be lost (this is reason enough to apply the
                       technique you offer).  In the end, there's no error in
                       your text, but I think that the code and the
                       formulation makes the reader focus on the wrong aspects
                       of the problem."

   5/13/98 lc  Item 47 Using a function-local static object to guarantee
                       initialization of non-local static objects isn't thread
                       safe.  This is true, but adding thread safety is hard,
                       especially if you also want to prevent resource leaks.
                       For details, consult John Vlisside's June 1996 C++ Report
                       article.  It discusses this and related issues.

  10/31/98 sdm 202-205 In his column in the October 1998 C++ Report, 
                       Herb Sutter describes an alternative design that allows
                       MyPerson to redefine PersonInfo's virtual functions
                       without actually inheriting from PersonInfo (though
                       inheritance is involved elsewhere).  Note that though this
                       discussion takes place in my Item devoted to MI, this
                       particular aspect of the design is not in any way
                       dependent on MI.

  !  7/13/00 ykc   207  This design can't work, because code like this,

                          CartoonCharacter *pc = new Cricket;
  
                        is ambiguous: Cricket inherits from CartoonCharacter twice
                        (once directly, once through Grasshopper).

Who's who:

  das = David Smallberg         
  ds  = Daniel Steinberg       
  apm = Arunprasad P. Marathe  
  dxs = Doug Stapp             
  ncm = Nathan Myers           
  rh  = Robert Hall            
  gb  = Gary Bartlett          
  mt  = Michael Tamm           
  kb  = Kendall Beaman         
  kd  = Keith Derrick          
  dqs = Dave Schneider         
  jg  = Joe Gottman            
  max = Max Hailperin          
  rmw = Richard Weeks          
  vb  = Valentin Bonnard       
  kga = Klaus-Georg Adams      
  jh  = Jun He                 
  tk  = Tim King               
  en  = Eric Nagler            
  th  = Ted Hill               
  dm  = Don Maier              
  rhs = Bobby Schmidt          
  mgh = Mark Harrison          
  wbr = William Rubin          
  mmr = Michael Rubenstein     
  mdr = Mark Rodgers           
  dxg = David Goh              
   bc = Brenton Cooper         
   lc = Laurent Chardonnens    
  atc = Andy Thomas-Cramer     
  axt = Antoine Trux           
  axm = Alex Marmer            
  jww = John Wait 
   bs = Brian Sharon           
   lf = Liam Fitzpatrick       
   gy = Gary Yee               
  joh = John O'Hanley          
   bp = Brady Patterson        
   cp = Christopher Peterson   
   da = Darin Adler            
   fk = Feliks Kluzniak        
   mp = Mark Pietras           
   dh = Dave Harris            
  jxg = Jörg Barfurth
  ivr = Igor Rafienko          
   id = Isi Dunietz            
   bm = Bernd Mohr  
   bk = Bill Kempf  
  ccr = Christopher Creutzi
   ms = Mark Stickel
  ykc = Yi-Kan Cheng
   ch = Claus Hoeltzcke         
   cb = Clay Budin              
  cbs = ChangBae Suh            
   ic = Ian Cooper              
  cxh = Carl Harris             
   pm = Panayotis Matsinopoulos 
   ph = P. Haution              
   tm = Tomasz Muldner          
   hs = Herb Sutter 
  bxp = Balog Pal
   lz = Leor Zolman        
   ga = Giulio Agostini    
  pxm = Pajo Misljencevic  
   js = Jimmy Snyder       
  jcj = Jeffrey Jacobs  
   fb = Fredrik Blomqvist 
   ai = Aaron Isaksen    
   es = Eugene Surman    
   yy = Yang Yinghua
   wk = Witold Kuzminski   
   mh = Matthias Hofmann   
   ya = Yuval Aharoni      
   kk = Kazunobu Kuriyama  
   ma = Michael Anderson   
   bj = Byrial Jensen      
  dys = Dirk Schreib       
   sf = Shmulik Flint        
   sv = Suzanne Vogel        
   ss = Sachin Shenoy        
   mc = Michael Christensen  
  dfc = Diego Funes   
   sn = Santha Nirmala
  jyt = Jorge Yáñez Teruel
   md = Mark Davis        
   mr = Marty Rabinowitz
   al = Ares Lagae
   am = Alexander Medvedev 
   mm = Marlene Miller
  bxs = Balbir Singh
  txz = Tal Zur
  lxz = Lyle Ziegelmiller
  lfr = Fraser Ross