Scott Meyers

Modification History and Errata List for More Effective C++

Last Updated October 18, 2012
by Scott Meyers

What follows are my notes on what I've changed in More 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 second printing, the changes made to the first printing 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 More Effective C++. To submit comments, send email to mec++@aristeia.com or write to the address listed on page 8 of the book's Introduction.

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

The following changes were made for the second printing. You need to worry about these changes only if you have a copy of the first printing of the book:

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
   2/ 7/96 msf    14  The comment in the call to updateViaRef should     2/20/96
                      say the call is to that function, not to update. 
                      
   2/21/96  ml    31  " ... attempting to perform the assignment."  -->  2/21/96
                      " ... attempting to perform the comparison." 
 
   1/28/96 jep    40  The placement new example is in Item 4, not        2/20/96
                      Item 3.
 
   2/12/96  wg    44  In 2nd paragraph, "reliability" --> "reliably"     2/20/96
 
   2/23/96  lh    70  Declaration of Validation_error::what fails to     2/25/96
                      put a space after the "*" in the return type. 

   1/28/96 jep    76  "You can set it up IT like this."                  2/20/96
                
   2/ 5/96 jep   111  Replace postfix ++/-- with prefix ++/-- for        2/20/96
                 189  stylistic consistency (in accord with Item 6).
                 191
               193-4
                 225
               
   2/ 5/96  tu   113  The text says a vtbl is an array of pointers to    2/20/96
                      non-member functions, but the diagrams clearly
                      show that the pointers ARE to member functions.
                      Find a way to rephrase this to make it true.
 
   2/ 5/96 jep   117  End of number 2: This cost of this step --> The    2/20/96
                      cost of this step .

 ! 2/ 3/96 sdm   120  The figures should show A having a vptr and D      2/20/96
                 242  having none.  See ARM pp. 234-5.

   2/ 5/96  tu   127  The formal parameter in the declaration of the     2/20/96
                      copy constructor should be "rhs".    

 ! 2/11/96  ds   146  UPNumber::destroy should be a const member         2/20/96
                      function.  Otherwise it is not possible to delete
                      a pointer-to-const.
 
   2/21/96 clt   146  The comment pointing out that declaration of a     2/25/96
                      UPNumber is legal, but its destruction is
                      illegal should be clarified a bit.
                      
   1/14/96 sdm   163  Sentence ends with a comma instead of a period     2/20/96
                      in the second line of text on the page.
 
 ! 2/ 5/96 jep   188  value->++refCount --> ++value->refCount.           2/20/96
  
   2/ 3/96 sdm 191-2  Various problems with figures:  arrow heads or     2/20/96
                 242  tails fail to properly abut ovals;  boxes fail
                 185  to abut properly.
                 114
                 117
               120-1
               187-8
                 248
                 266
              
 ! 1/25/96 lsk   207  The call to removeReference in String::operator[]  2/20/96
                      should not be there:  the call to
                      RCPtr::operator= will make the necessary
                      call to adjust the reference count.
 
   2/ 5/96 sdm   273  Modify the typesetting of "__cplusplus" so it's    2/20/96
                 295  clear there are two leading underscores.
  
   1/28/96 jep   280  "And of THE course the STL consists"               2/20/96

The following changes were made for the third printing. You need to worry about these changes only if you have a copy of the first two printings of the book:

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  -------- 
 ! 3/21/96 sdm   163  In March 1996, the committee changed the auto_ptr  4/30/96
                 165  interface so that, among other things, the copy
                 166  ctor and assignment operators now take const
                 291  parameters.  I added footnotes generally noting
                      the changes and referred readers to 
                      updated auto_ptr information at the MEC++ WWW
                      and FTP sites. 

   4/26/96 psrc  177  In sixth line from bottom, "SmartPtr" is in wrong  4/29/96
                      font. 
                 
   4/11/96 sdm   181  Improper alignment of comment near the bottom of   4/29/96
                      the page.
                 
   4/30/96 avk   187  In 3rd paragraph, the text implies that the        4/30/96
                      String ctor sets the reference count to 1, but 
                      that is actually done by the StringValue ctor.  
                      Reword.

 ! 3/19/96 sdm   209  RCIPtr<T>::init refers to counter->pointee         4/30/96
                      before it is initialized.  Change the second if
                      statement to:
                      
                        if (counter->isShareable() == false) {
                          T *oldValue = counter->pointee; 
                          counter = new CountHolder;
                          counter->pointee = new T(*oldValue);
                        }
                       
 ! 3/ 4/96  we   209  RCWidget fails to perform a copy-on-write (COW)    4/30/96
                 210  when non-const member functions are invoked.
                      This is incorrect:  each non-const member
                      function might modify the (shared) Widget the
                      RCWidget points to.  To rectify the problem, add
                      an overloaded non-const version of operator-> and
                      operator* to the RCIPtr template, and have these
                      functions perform the COW before returning.  This
                      bends the notion of constness, because we're using
                      non-const operators -> and * even though there is
                      no conceptual change in what the smart pointer
                      points to, but that's preferable to having
                      incorrect behavior.  (Note:  This change is later
                      revoked.  See the explanation below for why.)

 ! 3/21/96 jj 222-223 The calls to removeReference in the two            4/30/96
                      String::operator= functions should not be there:
                      the calls to RCPtr::operator= will make the
                      necessary calls to adjust the reference counts.
 
   3/ 6/96  lh   237  There is no such thing as a "static member" of a   4/29/96
                      function.  Reword the second-to-last paragraph.

 ! 3/ 5/96  sk   264  The destructor in AbstractAnimal should be         4/30/96
                      public, not protected.

 ! 3/31/96 rcn   293  auto_ptr's reset function should make sure that    4/30/96
                      p and pointee are different before doing
                      anything, otherwise pointee will end up pointing
                      to a deleted object.  (In practice, this is a moot
                      point, because the revised auto_ptr defintion
                      (see point above) contains no "reset" member
                      function.) 

The following changes were made for the fourth printing. You need to worry about these changes only if you have a copy of the first three printings of the book:

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
   8/31/96  mb    13  Change "cannot change the constness of an          9/26/96
                      expression" to "cannot remove the constness from
                      an expression".

   3/18/96 aid    34  Many compilers fail to enforce the restriction     4/29/96
                      that const objects returned from functions may
                      invoke only const member functions.  Add a
                      footnote noting common non-compliance with
                      the standard.

   1/30/96 sdm  45,66 All figures with curves look bad:  the curves      9/26/96
              117,119 are clearly being approximated by line segments.
              124,150
              151,173
              178,181
              184,185
              187,188
              191,192
              203,208
              229,248
              258,264
              266
                     
 ! 4/ 9/96  ks    57  If initAudioClip gets an exception from the call   4/30/96
                      to new AudioClip, it will call cleanup in the try
                      block, and cleanup will delete theAudioClip.  But
                      theAudioClip will not yet have been initialized.
                      Instead of calling cleanup in the catch block, 
                      manually delete theImage.

   7/29/96  sm    64  Change "that" to "that that" at the beginning of   9/26/96
                      the third line up from the parenthetical
                      paragraph. 

   2/18/96 clt    67  Paragraph beginning with "Furthermore,             9/26/96
                      conversions from typed to untyped pointers..."
                      needs a new beginning to clarify that this is
                      the second of the two types of conversions
                      signposted by the last paragraph on page 66.
                      The next paragraph (beginning with "Even here, 
                      however") marks the beginning of the final 
                      difference between parameter passing and exception 
                      throwing, and it needs a clearer introduction, too.
                      
   9/26/96 sdm    67  Modify the catch clause taking a void* to take a   9/26/96
                      const void*.  Otherwise it wouldn't be possible
                      to catch an exception of type const T*.
 
   3/ 6/96  jm    70  exception::what has an exception spec, but that    4/29/96
                      notion isn't introduced until Item 14.  Add an
                      xref to the comment so readers who don't know
                      about exception specifications will understand.
  
   5/30/96  sb    74  In the third paragraph, I refer to "two cases"     9/26/96
                      that are easy to forget.  There is no second
                      case.  Reword.
                       
   5/30/96  sb    90  Wrong font for initial "t" in the pseudocode,      9/26/96
                      "the appropriate data from the database"
 
   1/28/96 jep   107  Some compilers don't create a temporary in this    4/29/96
                 109  expression: 
                            Rational(lhs)
                      Instead, they (incorrectly) cast away the
                      constness of lhs and return a reference to that!
                      Advise readers to test their compilers before
                      using this technique.

 ! 7/19/96 sdm   109  In July 1996, the standardization committee        9/26/96
                      decided that named objects may be treated
                      essentially the same as unnamed objects for
                      purposes of performing the return value
                      optimization.  I added a footnote to this effect.

   7/ 9/96 ahd   111  There is no need to #include <math.h> for this     9/26/96
                      program.  Also, the logarithms are natural, not
                      base 10.
 
 ! 7/23/96  um   115  The statement that abstract classes generally      9/26/96
                      have no vtbl is incorrect.  A vtbl is needed for
                      such classes in case virtual functions are called
                      during construction/destruction of instances of
                      such classes.
   
   4/16/96 tjb   129  In second line, the closing parenthesis is in the  4/29/96
                      wrong font.

 ! 5/15/96 sdm   134  Add footnote:                                      9/26/96
                        In July 1996, the ISO/ANSI standardization
                        committee changed the default linkage of inline
                        functions to external, so the problem I
                        describe here has been eliminated, at least on
                        paper. Your compilers may not yet be in accord
                        with the emerging standard, however, so your
                        best bet is still to shy away from inline
                        functions with static data.   

   3/ 6/96  lh   155  The comment in isOnHeap refers to "the memory      4/29/96
                      occupied by ptr."  It should refer to "the memory
                      occupied by *this."
                      
   4/10/96 tjb   160  In comment:  "defererence" --> "dereference"       4/29/96

   5/20/96 sdm   166  Should explicitly mention that sometimes a smart   9/26/96
                      pointer does NOT delete what it points to in its
                      destructor, otherwise people may think that ALL
                      smart pointers do that.

   7/16/96 sdm   169  Replace "iff" in the comment with "if and only     9/26/96
                      if."  Some programmers were unfamiliar with what
                      I thought was a common abbreviation.

   9/ 7/96 sdm   178  In first paragraph, T1 and T2 should be T1* and    9/26/96
                      T2*, respectively.
                      
   7/ 5/96  os   180  The text in the middle of the page talks about     9/26/96
                      assigning non-consts to consts, but the examples
                      show initializations.  Modify the text to refer
                      to both initializations and assignments.

   5/11/96  en   191  In comment, "refcount" --> "refCount"              9/26/96

   7/ 5/96  os   209  The test of counter against 0 at the top of        9/26/96
                 210  RCIPtr::init is unnecessary, because counter can
                      never be null.  Eliminate the test.  Ditto for
                      the test of counter inside the RCIPtr destructor
                      and assignment operator.

   7/19/96  os   254  I refer to RTTI-based "switch-on-type"             9/26/96
                      statements, but it's not legal to switch on the
                      return value of a call to typeid.  Reword.

 ! 7/31/96 sdm   276  The statement at the beginning of the second       9/26/96
                      paragraph that C and C++ have different layout
                      rules for structs is incorrect.  The rules are
                      the same.

 ! 7/20/96 sdm   292  The auto_ptr class definition needs to add this:   9/26/96
                 293                   
                 294    template<class U> friend class auto_ptr<U>
                        
                      This makes auto_ptr<T> a friend of auto_ptr<U>
                      for all T and U, i.e., all auto_ptr classes are
                      friends of one another.  This is necessary to
                      allow auto_ptr<T> to access the dumb pointer
                      inside auto_ptr<U>, which it does inside the
                      bodies of its member function templates for
                      copying and assignment. 

The following changes were made for the sixth printing. You need to worry about these changes only if you have a copy of the first five printings of the book:

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
  11/15/97 sdm   xiv  Moved some text from the bottom of page xiv to    11/15/97
                 xv   the top of page xv to make more room on xiv for 
                      the names of people who've reported bugs.

   8/21/97 sdm     8  Change email contact address to                   11/14/97
                      mec++@awl.com.

 ! 5/29/96  js    13  sw is defined as a const object, and the results  11/14/97
                      of modifying a truly const object -- even after
                      applying a const_cast -- are undefined.  I 
                      modified the example to eliminate the problem.
                      
  11/ 3/97 mm     14  In the declaration of updateViaRef, the           11/14/97
                      ampersand should be next to the type name(not 
                      the parameter name) in order to be consistent 
                      with the style I use throughout the book.

 !11/11/96 ymk    15  The new cast approximations need an extra set     11/14/97
                      of parens.  They should be as follows:
                      
                        #define static_cast(TYPE,EXPR) ((TYPE)(EXPR))
                        
                      Otherwise casts like this don't work correctly:
                      
                        static_cast(int*, my_vec)[j]

   4/18/97 drk    19  It's not true that all legal workers in the USA   11/14/97
                      must have a Social Security Number.  I removed 
                      the example.

   4/22/97 sdm    20  Define bestPieces example like this:              11/14/97
   
                          EquipmentPiece bestPieces[] = {
                            EquipmentPiece(ID1),
                            EquipmentPiece(ID2),
                            ...
                            EquipmentPiece(ID10)
                          };                    

                      This makes it easier for readers to figure out
                      how it generalizes to constructors that take
                      multiple arguments. 

   1/15/97 ras    36  The comma operator occurs more often than I       11/14/97
                      suggest, but the most common place to see it is
                      still probably within a for loop.  I reworded
                      the paragraph.

 !12/25/96 dmp    43  In the first full paragraph on the page, I say    11/14/97
                      there is "only one global operator new."  This
                      isn't true.  There are actually several forms of
                      operator new at global scope, but only one has
                      the "normal" form, i.e., takes exactly one
                      argument of type size_t.  I reworded the paragraph
                      to eliminate the inaccuracy.

   1/17/97  dh    59  In the first paragraph, change "if an exception   11/14/97
                      is thrown while another is active" to "if control 
                      leaves a destructor due to an exception while
                      another exception is active".  It is legal for an
                      exception to be thrown while you're in the catch
                      clause of an active exception.

   3/26/97 sdm    66  Update diagram to include new underflow_error     11/14/97
                      class that was added to the standard. 

 ! 4/15/96  jr    75  The C++ standard inexplicably forbids             11/14/97
           dcs        exception specifications in typedefs, so
                      CallBackPtr cannot be a typedef here, at least
                      not portably.  As it turns out, both compilers I
                      tested accepted the typedef anyay.  I added a
                      footnote explaining the situation and suggesting
                      that portable code would have to use a macro
                      instead of a typedef.

   1/31/97  gm   113  "Each class in a program has its own vtbl" -->    11/14/97
                      "Each class in a program that declares or
                      inherits virtual functions has its own vtbl"

   4/ 4/97 sdm   114  Line too thick in lower figure.                   11/14/97
   
   4/ 4/97 sdm   115  The first sentence could be misleading: the size  11/14/97
                      of a class's vtbl is proportional to the total
                      number of virtual functions declared for a class,
                      including those declared in base classes.  Note
                      that it's based on DECLARATIONS, not definitions.
                      I reworded things.
                      
   4/10/97 sdm   115  The vtbl is often put in the object file          11/14/97
                      containing the definition of the first 
                      non-inline *non-pure* virtual function.
                      
   4/ 4/97 dab   115  The vtbl for C1 would be placed in the object     11/14/97
                      file containing the definition of C1::~C1, not
                      C1::f1. 
                      
  10/27/97 sdm   118  The virtual call really translates into this,     11/14/97

                        (*pC1->vptr[i](pC1);

                      because each member function has the "this" 
                      pointer passed in from the call site.

 ! 1/ 4/97  ih   119  In my discussion of virtual base classes, I       11/14/97
                 120  claim that virtual base pointers must be stored
                      inside objects.  This is not true. Some 
                      implementations put them inside class vtbls.  I 
                      reworded things to make clearer that the 
                      implementation I show in the book is not the only 
                      implementation in use.
                      
   6/19/97  lw   167  editTuple's parameter should be passed by         11/14/97
                      reference, just like it is on page 161.

  10/ 3/97  jl   200  There is no need for RCPtr<StringValue> to be a   11/14/97
                 201  friend of String.  The entire first prose
                 204  paragraph on page 200 is incorrect.  (I don't 
                      know what I was thinking when I wrote it.)  I
                      eliminated the friend declarations wherever they
                      occured, removed the offending paragraph, and
                      moved some text from page 201 to page 200 to 
                      avoid having page 200 be too gruesomely empty.

   5/12/97 rxc   204  Make RCObject's destructor pure virtual to match  11/14/97
                      the initial declaration on page 194.

   1/15/97 ras   236  The behavior of SpaceShip::lookup does not depend 11/15/97
                 238  on any SpaceShip data members, so it should be a
                 239  static member function.  I also removed the const
                 240  from the function, because only non-static
                      member functions may be const.
                      
  11/14/97 sdm   240  In first sentence, "we probably have to pay" -->  11/15/97
                      "we may have to pay".  Some compilers are likely
                      to apply the return value optimization (see 
                      Item 20) to avoid copying the map.

  11/14/97 sdm   242  In first sentence, "likely object layout" -->     11/15/97
                      "possible object layout".  See comment above for
                      changes to pages 119-120.

  10/15/97 clf   270  In 1st paragraph, "forego" --> "forgo"            11/14/97

   9/24/97 sdm   286  I updated the book information to refer to the    11/14/97
                 289  latest editions of The C++ Programming 
                      Language and Effective C++ and to mention the 
                      CD version of Design Patterns.

  11/14/97 sdm   289  I removed the footnote saying I'm a columnist     11/14/97
                      for C++ Report, as my last column appeared 
                      there at the end of 1996.

The following changes were made for the seventh printing. You need to worry about these changes only if you have a copy of the first six printings of the book:

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
   1/??/98 jww    vi  The date for the sixth printing was listed as     11/??/98
                      December 1998, but that printing was actually 
                      made in December 1997.  The date for the seventh 
                      printing is correctly listed as November 1998.  So,
                      no, the sixth printing is not more recent than the
                      seventh printing!

  10/15/97 clf ix,x,  For consistency with Effective C++, I should add   6/10/98
               9,12,  a period to the end of the title for each Item.
              16,19,
              24,31,
              35,38,
              45,50, 
              58,61,
              68,72,
              78,82,
              85,93,
             98,101,
            105,107,
            110,113,
            123,130,
            145,159,
            183,213,
            228,252,
            258,270,
                 277

   6/22/98 sdm  xiii  The C User's Journal is now the                    6/27/98
                      C/C++ Users Journal.

   6/22/98 sdm   xiv  Borland is now Inprise.                            6/27/98

  12/29/97 sdm   xiv  Updated acknowledgements to include most recent   12/29/97
                  xv  bug reporters.  (This modified a page break.)  
                      
  12/ 3/97 sdm   xiv  ANSI/ISO --> ISO/ANSI.                            12/29/97
                   2
                  59
                  96
                 109
                 134
                 256
                 277
                 285
    
  12/ 4/97 sdm     1  On 11/14/97, the ISO and ANSI standardization     12/29/97
                   2  committees adopted what can be referred to as an
                 134  official standard for C++, so all references to
                 277  "draft standard," "nascent standard," "DIS,"
                 278  etc. should refer to just "the standard."
                 279  
                 285 

   6/25/98 sdm     2  In second line, "the accumulated wisdom" ==>       6/27/98
                      "accumulated wisdom"

   6/25/98 sdm     3  In second paragraph, "i.e." ==> "e.g."             6/27/98

   6/ 7/98 sdm  4 27  "string class" ==> "string type".  As I explain    6/ 7/98
                  85  on page 279, string is not a class, it's a typedef
                 183  for an instantiation of the basic_string template.
             192 217
             256 278
             279 280

  12/30/97 sdm     4  Replaced HP's STL FTP site with SGI's STL WWW     12/30/97
                 302  site. WWW is more convenient for many people,
                      and the SGI software is more up-to-date.  I had
                      to eliminate two index entries when I did this.

   6/ 7/98 sdm     5  The third paragraph states that I use different    6/ 7/98
                      notations for inheritance in this book and in
                      Effective C++, but that's true only for the 
                      first edition of EC++.  I added clarifying text.

  12/29/97 sdm     8  www.aw.com --> www.awl.com;                       12/29/97
                 287  ftp.aw.com --> ftp.awl.com

   6/25/98 sdm    11  At end of second-to-last paragraph, note that      6/27/98
                      Item 30 describes an interesting exception to the
                      rule that operator[] should return a reference.

   6/25/98 sdm 13,52, Bad line breaks.                                   6/27/98
               58,76,
                 265

   6/25/98 sdm    14  In second-to-last paragraph, "almost certainly     6/27/98
                      want a static_cast" ==> "probaby want a
                      static_cast".

  11/14/97 sdm 14,34, Footnote symbols are followed by a period.  The   12/29/97
               48,59, periods shouldn't be there (and they're not in 
               75,96, EC++/2E).
                 109
                 134
                 166
                 291

   5/ 5/98 rxb    21  In 6th line on page, "treated as a" ==>            6/ 3/98
                      "treated as an"

  12/30/97 sdm    40  Replace or supplement header names ending in .h   12/30/97
                  65  with new extensionless header names.
                 111

  12/14/97 sdm    42  "different ... than" --> "different ... from".    12/29/97
                 223

  12/29/97 sdm    48  Added to the parenthetical comment about using    12/29/97
                      auto_ptr-like classes for arrays the suggestion 
                      that using a vector in such cases might well be 
                      better.

 !11/20/97 kga    48  The auto_ptr interface in the book and at the web 12/27/97
           sdm   163  site doesn't show the most recent interface,
                 165  which is nearly identical to the interface I
                 166  described in the original printing of MEC++.
                 291  Update book and site to be in accord with the
                      interface approved at the 11/97 ISO/ANSI
                      meeting.  This requires removing the
                      auto_ptr-related footnotes I noted above on
                      3/21/96.

   6/26/98 sdm    52  In the first paragraph, it's misleading to refer   6/27/98
                      to arguments that are "non-null".  The arguments
                      are references, and as Item 1 explains,
                      references can't be null.  "non-null" ==>
                      "non-empty strings".

  12/29/97 sdm    59  Modified footnote wording in light of greater     12/29/97
                  96  compiler support for features mentioned in the
                      footnotes. 

   1/ 1/98 sdm    99  unsigned int ==> size_t                            6/ 3/98
                 135
             139-140 

 ! 2/ 6/98 sdm   101  As noted in the footnote on page 109 (added on     6/ 6/98
                 104  9/26/96), and contrary to the text on these pages,
                 109  compilers may now apply the same optimizations to
                 110  named objects that they've always been able to 
                      apply to unnamed objects.  I reworded things 
                      and/or added clarifying footnotes, and one result
                      was that the information formerly in the footnote 
                      on page 109 ended up in a new footnote on page 104.

   2/ 6/98 sdm   118  There are now more approaches to implementing      6/ 7/98
                 119  virtual base classes than there used to be, and 
                 120  some of the alternative approaches incur a smaller
                 121  space overhead.  For details, consult pp. 95-101
                      of Stan Lippman's "Inside the C++ Object Model"
                      (Addison-Wesley, 1996).  I modified the text on
                      these pages (including the table on page 121) to
                      make it clear that the implementation of virtual
                      bases I describe in the book is not the only
                      implementation in use.

   6/26/98 sdm   140  Added comment "// see below" to end of line        6/27/98
                      declaring maxObjects with an initial value.

   6/ 6/98 sdm   140  For consistency with numObjects, type of           6/ 6/98
                 141  maxObjects should be size_t, not int.
                 142
                 145

  12/29/97 sdm   141  "many compilers" ==> "some compilers".  The       12/29/97
                 262  state of compilers has improved since I
                      originally wrote the book in 1995.

   2/24/98 cxm   142  maxObjects should be const.                        6/ 6/98
                 145

   2/24/98 cxm   144  In last line on page, "Counter<Printer>" should    6/ 6/98
                      be "Counted<Printer>".  

   6/26/98 sdm   161  In comment above LogEntry definition,              6/27/98
                      "template class" ==> "class template"

  12/29/97 sdm   165  "transferral" ==> "transferal"                    12/29/97 
                      
   6/26/98 sdm   166  In last paragraph, mention that returning an       6/27/98
                      object instead of a reference leads to the
                      slicing problem, and provide an xref to Item 13.

   4/ 6/96 edw   190  The const version of operator[] should return a    6/ 6/98
   2/ 6/98 sdm   204  const char& instead of a char.  Otherwise it's
                 207  not possible to do this:
                 218    String s;
                        ...
                        const char *p = &s[2];
                      This is also important for efficiency when char 
                      is generalized to an arbitrary type.
                      
   2/ 6/98 sdm   192  The standard string type adopts a combination of   6/ 7/98
                 193  approaches 2 and 3:  the reference returned from 
                      the non-const operator[] is guaranteed to be valid
                      only until the next operation that might modify the
                      string.  I added a footnote to this effect,
                      and this changed the page break.
                      
   2/ 6/98 sdm   199  Comment at beginning of RCPtr template isn't       6/ 6/98
                      quite true.  T must support the RCObject
                      interface, but it need not inherit from
                      RCObject.  This is explictly mentioned on page
                      201.

   2/ 6/98 sdm   208  Bad break in "CountHolder" in last prose           6/ 6/98
                      paragraph. 

   2/ 6/98 sdm   220  Near the end of third line from bottom, insert     6/ 6/98
                      "so" between "CharProxy," and "the".

 ! 2/19/98 dxg   224  In String::CharProxy::operator&, there should be   6/ 6/98
                      no call to removeReference, because the assignment
                      statement on the next line will automatically take
                      care of it.  (See also the bug report above of
                      3/21/96 for pages 222-223.)

   2/ 6/98 sdm   226  "non-const references" ==> "references to          6/ 6/98
                      non-const objects"

   6/26/98 sdm 228-29 "a direction and a velocity" ==> "a velocity".     6/27/98
                      More than one person has sternly pointed out to 
                      me that velocity is a vector quantity, hence 
                      always includes a direction. (This changed a 
                      page break.)

   2/ 6/98 sdm   230  "seat-belts" ==> "seat belts"                      6/ 6/98

 ! 2/ 6/98 sdm   238  According to the standard, the value returned      6/ 6/98
                      from type_info::name is implementation-defined.
                      In practice, different implementations do 
                      different things.  I added a footnote clarifying 
                      the situation.  (See the "Interesting comment" 
                      below about Item 31 for more information on this 
                      topic.)

   6/ 4/98 sdm   280  Last line on page isn't correctly justified.       6/ 5/98

The following changes were made for the eighth printing. You need to worry about these changes only if you have a copy of the first seven printings of the book:

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
  11/14/98 bwk    xi  Note that it's the first edition of Hennessy's     5/ 5/99
                      and Patterson's book that was published in 1990.
                      A second edition was published in 1996.

                 xiv  Added new bug reporters to acknowledgements.       5/ 5/99

   4/ 7/99 jsh    14  The comment in the code attempting to do a         5/ 5/99
                      dynamic_cast to a double is misleading.  The
                      problem is not that inheritance isn't involved,
                      it's that the type being cast (firstNumber)
                      doesn't have any virtual functions.  Even if
                      inheritance was present, if the type being cast
                      lacked virtual functions, the code still
                      wouldn't compile.

   3/10/99 mr     66  The ellipses after the "throw value" can never     5/ 5/99
                      be reached.  The "..." should go after the "}", 
                      not before it. 

   4/ 6/99 rhs    96  The footnote at the bottom of the page states      5/ 5/99
                      that all STL iterators must support operator->,
                      but that's not quite true: output iterators need
                      not support it.  In the case of the example in
                      the book, map::find returns a bidirectional
                      iterator, not an output iterator, so the
                      footnote is accurate for the example.  I modified
                      the footnote to say that *most* STL iterators 
                      are required to support operator->.

 ! 4/21/99 ea    149  At the bottom of the page, steps 3 and 4 should    5/ 5/99
                      be reversed.  The second object is a parameter
                      for the first object's constructor, so the
                      second object must be constructed before the
                      first one is.
                      
  12/ 8/98 cwg   250  Disagreement in number in the second               5/ 5/99
                      parenthetical remark in the paragraph at the top
                      of the page: "effect" ... "are".  Ugh.

The following changes were made for the ninth printing. You need to worry about these changes only if you have a copy of the first eight printings of the book:

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
                 xiv  Added new bug reporters to acknowledgements.      10/ 4/99

  10/ 3/99 sdm     8  Added mention of my mailing list, which, among    10/ 4/99
                      other things, announces each time this errata 
                      list is updated. 

 ! 7/ 2/99 sdm    21  In the loop in the code at the top of the page,   10/ 4/99
                      the statement 
 
                        new (&bestPieces[i]) EquipmentPiece (ID Number);
 
                      should be
 
                        new (bestPieces+i) EquipmentPiece (ID Number);
 
                      The form using "&bestPieces[i]" has two
                      problems.  Strictly speaking, it yields
                      undefined results, because the bestPieces[i]
                      object hasn't yet been constructed, so referring
                      to it is undefined.  (In practice, this is
                      unlikely to be a problem, as any decent compiler
                      will look only at its address.)  Second, if
                      EquipmentPiece has defined its own operator&,
                      "&bestPieces[i]" might not do what you expect.
                      Using the "bestPieces+i" form avoids both
                      problems.
 
   6/24/99 pab    56  The functions initImage and initAudioClip should  10/ 4/99
                      be static member functions, because (1) they
                      need no "this" pointer and (2) they are called
                      before the data members of the object have been
                      initialized.

   6/24/99 ea    149  In the discussion that follows this code,         10/ 4/99

                        new UPNumber(*new UPNumber)

                      I refer to the "first object" and the "second
                      object", but I fail to make clear which is
                      which.  The "first object" is the leftmost one
                      above, and the "second object" is the one passed
                      to the constructor of the first.

The following changes were made for the tenth printing. You need to worry about these changes only if you have a copy of the first nine printings of the book:

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
   4/10/00 km     51  In the first paragraph, the cross reference to     6/ 4/00
                      Item 3 should be to Item 4.

 ! 1/ 1/00 em     56  Contrary to the bug report from pab of 6/24/99     6/ 4/00
                      that I implemented on 10/4/99, initImage and
                      initAudioClip should NOT be static, because
                      initAudioClip uses delete on theImage, and
                      theImage is a nonstatic data member.  (Strictly
                      speaking, initImage could be static, but it's
                      better to declare the two init functions
                      similarly.  Better still is to follow the
                      ultimate advice of this Item and use auto_ptr
                      data members instead of the approach based on
                      init functions.)

  11/ 2/99 fk     76  In line 20, missing space between "results" and    6/ 4/00
                      "in".  This error seems to have been introduced
                      in the seventh printing. 

 ! 9/16/98 ct    202  Suppose we have RCPtrs to linked list nodes,       6/ 4/00
                 206  i.e., RCPtr<LLNode> objects.  Consider:

                        RCPtr<LLNode> p;
                        ...
                        p = p->next;

                      This invokes RCPtr::operator=, where the
                      parameter rhs is bound (by reference) to
                      p->next.  Now consider this statement inside
                      RCPtr::operator=:

                        if (pointee) pointee->removeReference();

                      If removeReference() decrements the reference
                      count to 0, the LLNode pointed to by pointee
                      will be deleted.  But that allows an
                      implementation to trash the memory inside the
                      deleted object, including its "next" field --
                      which is what rhs is currently bound to!
                      Here's a fix:

                        template<class T>
                        RCPtr<T>& RCPtr<T>::operator=(const RCPtr& rhs)
                        {
                          if (pointee != rhs.pointee) {
                            T *oldPointee = pointee;
                            pointee = rhs.pointee;
                            init();
                            if (oldPointee)
                              oldPointee->removeReference();
                          }
                          return *this;
                        }

 ! 2/19/00 sdm   279  basic_string declaration near bottom of page is    6/ 4/00
                      incorrect. It should be

                        template<class charT, 
                                 class traits = char_traits<charT>,
                                 class Allocator = allocator<charT> >
                        class basic_string;

   5/28/00 sdm   316  RCIPtr::makeCopy is missing from the index.        6/ 4/00

The following changes were made for the twelfth printing. You need to worry about these changes only if you have a copy of the first eleven printings of the book:

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
   6/ 5/00 sdm   xiv  Remove js2 from the acknowledgements, because his  9/13/01
                      bug report was rejected at the very last minute
                      when making revisions for the tenth printing.

   3/30/01 sdm     2  Material in the book is based on the final C++     9/13/01
                      Standard, not the DIS.

 ! 6/24/00 nxd    16  Macro expansion for dynamic_cast should have       9/13/01
                      parens around "(TYPE)(EXPR)", just like it
                      does for the other casting macros on page 15.

   9/ 6/00 bp     33  In accord with my advice in Item 21 of             9/13/01
                      Effective C++ to "use const whenever possible,"
                      oldValue should be declared const in the code 
                      example at the top of the page.

   2/21/01 wds    58  In second paragraph, "initializationof" ==>        9/13/01
                      "initialization of".

 ! 8/15/00 wcm   142  For consistency with the changes I made on         9/13/01
                 144  6/6/98 (see above), the Counted template should 
                      have objectCount return a size_t instead of an int,
                      and numObjects should be of type size_t, not int.

  11/ 2/99 fk    152  The last sentence of paragraph 2 begins with "As   9/13/01
                      such, ...".  "As such" isn't really correct here.  
                      Reword.

   7/21/00 sdm   177  Italicized text on this page has jaggies.          9/13/01
                      Regenerate PDF and reprint.

The following changes were made for the thirteenth printing. You need to worry about these changes only if you have a copy of the first twelve printings of the book:

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
   1/25/02 csp     4  In last line,                                      7/12/02
                      http://www.sgi.com/Technology/STL/ ==>
                      http://www.sgi.com/tech/stl/

  12/20/01 pd     11  Reword final paragraph to indicate that            7/12/02
                      references are preferable to pointers when

                        there will always be an object to refer to
                        AND
                        you'll always want to refer to the same object

                        OR

                        you're implementing an operator whose
                        syntactic requirements disallow pointers

   1/ 8/02 sdm    52  Bad line break: "theAudi-oClip" ==>                7/12/02
                      "theAudio-Clip"

  11/ 2/99 fk     54  In the first prose paragraph, I remark that "As    7/12/02
                      fully constructed objects, these data members
                      will be automatically destroyed when the
                      BookEntry object containing them is..."  This is
                      slightly misleading.  Because an exception is
                      thrown, no BookEntry object will be created,
                      hence none will be destroyed.  Rather, the fully
                      constructed BookEntry data members will be
                      automatically destroyed as C++ backs out of
                      construction of the object it had been
                      attempting to construct.  The important point is
                      this: because the data members of the would-be
                      BookEntry object have been fully constructed,
                      C++ must see to it that they are also
                      destructed.

  10/ 1/01 jfn    56  In the last sentence before the code example at    7/12/02
                      the bottom of the page, "private static member
                      function" ==> "private member function".  This
                      is what I hope is the final undo for the 
                      incorrect "correction" I added on 10/4/99;  
                      consult em's correction reported on 1/1/00 for
                      details.

 !12/ 5/01 at  62-63  Contrary to what I state on these pages, Section   7/12/02
                      15.1/5 of the Standard makes clear that
                      implementations may optimize away the creation
                      of exception object under some conditions.
                      However, my remark that a catch block couldn't
                      modify localWidget continues to be true, as does
                      my observation that throwing an exception is
                      typically much slower than passing a parameter.

   1/ 8/02 sdm    76  Bad line break: "conver-tUnexpected" ==>           7/12/02
                      "convert-Unexpected"

  12/ 6/02 ddg    99  In last sentence "When countChar returns," ==>     7/12/02
                      "When the statement containing the call to 
                      countChar finishes executing,"

   3/12/01 wds   120  Bad hyphenation in 2nd-to-last para: "runt-ime"    7/12/02
                      ==> "run-time".

   3/21/00 sdm   152  The information at the "Comments on Item 27" web   7/12/02
                      site leads me to conclude that the second
                      paragraph on this page takes too hard a line. 
                      Reword to soften.

  1/19/00 ccr 186,193, Reference counts should be unsigned (i.e.,        7/14/02
              195,204 size_t), not int.  I also updated the 
                      on-line code for Item 29.

   1/19/00 ccr   204  The RCObject constructors and destructor are       7/14/02
                      declared protected here, but earlier in the book
                      they were public.  I made them public again, both
                      in the book and in the on-line source code.

   6/ 4/02 sdm   208  Bad line break in last prose paragraph:            7/12/02
                      "Coun-tHolder" ==> "Count-Holder".  (An entry
                      above for 2/6/98 says this was fixed on 6/6/98,
                      but apparently that fix got lost somewhere
                      between my computer and the printer.)

 ! 7/31/00 cw 209-210 cw notes that RCIPtr needs a way to make the       7/15/02
                      pointed-to object unshareable.  I note that
                      RCIPtr needs a way to find out whether the
                      pointed-to object is being shared.  I edited the
                      book to add a getRCObject member function, but
                      that solution's primary attraction is that it's
                      easy to implement.  If I were designing RCIPtr
                      from scratch, I might choose a different tack. 

 ! 3/22/01 wcm   209  RCPtr and RCIPtr behave inconsistently with        7/15/02
                 210  respect to automatically performing COW on 
                 316  pointee objects.  The fundamental problem is that
                      my fix for we's bug report of 3/4/96 above was
                      incorrect, and I should have realized that when I
                      had to "bend" the notion of constness to 
                      implement it.  The responsibility for performing  
                      COW rests not on smart pointers but on smart
                      pointer clients.  (Note how on page 207
                      the non-const String::operator[] creates a new
                      StringValue object.)  In responding to we's bug
                      report, I shouldn't have modified RCIPtr.
                      Instead, I should have modified RCWidget::doThis
                      to do a COW, and that's what the book does
                      now.  I also removed the modifications I
                      originally added to address we's bug report, and
                      I updated the Item 29 source code, too.

 ! 5/30/02 agb   210  makeCopy should invoke                             7/14/02
                      counter->markUnshareable() before returning.
                      (The need for this fix is obviated by the 
                      above-noted elimination of support for automatic
                      COW in RCIPtr.)

   9/22/01 sdm   222  Bad justification of last line on page.            7/12/02

 ! 5/ 7/02 mt    238  The footnote suggests identifying a class by the   7/12/02
                      address of its associated type_info object, but
                      there is no guarantee that each class has only
                      one type_info object.  In fact, I am now aware of
                      an implementation that generates multiple
                      type_info objects for a class.  I now believe
                      that the best way to identify classes is to wrap
                      type_info objects inside other objects that are
                      easier to work with.  Andrei Alexandrescu has
                      written such a wrapper class called TypeInfo,
                      described it in his Modern C++ Design, and
                      implemented it in his Loki library.

   5/ 5/02 ar    261  I should note that dynamic_cast throws an          7/12/02
                      exception only because it is a cast to a
                      reference.  dynamic_casting to a pointer would
                      return a null pointer if the cast failed.

The following changes were made for the seventeenth printing. You need to worry about these changes only if you have a copy of the first sixteen printings of the book:

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
  10/ 7/03 sdm   xiv  Font face and size for "Davide Gennaro" is        10/ 7/03
                      incorrect. 

   8/14/02 sdm 66-67  Clarify that the inheritance-based conversions    10/ 7/03
                      described on these pages apply only to public
                      inheritance.  (For non-public inheritance,
                      things get a bit more complicated.  For details,
                      including a rationale for the behavior, consult
                      the July 2001 column by Jim Hyslop
                      and Herb Sutter, "Baseless Exceptions.")

   1/ 6/03 ais    67  In the examples near the top of the page, note    10/ 7/03
                      that catch-by-value and catch-by-pointer is
                      generally a bad idea and reference Item 13,
                      which discusses why.

 ! 4/30/03 mh    209  RCIPtr<T>::init should test oldValue against NULL 10/ 7/03
                      before dereferencing it.   I also updated the 
                      on-line code for Item 29.

   6/ 8/03 sdm   265  Bad line break:  AbstractA-nimal ==> Abstract-    10/ 7/03
                      Animal

 ! 6/ 7/03 mh    266  2nd and 3rd paras discuss the assumption that     10/ 7/03
                      base classes have no data.  The correct 
                      assumption is that derived classes have no
                      data.  Revise discussion.

The following changes were made for the nineteenth printing. You need to worry about these changes only if you have a copy of the first eighteen printings of the book:

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
 ! 4/19/04 cc     50  The para after the first code fragment says that   7/24/04
                      the window will always be destroyed, even if an
                      exception is thrown, but this this true only if
                      the exception is caught.  If it's never caught, 
                      there is no guarantee that local objects will be
                      destroyed.

 ! 6/ 9/04 jw     70  In 3rd para, bad_typeid isn't thrown when a null   7/24/04
                      pointer is used with dynamic_cast, it's thrown 
                      when a null pointer is dereferenced in a call to
                      typeid.

The following changes were made for the twentieth printing. You need to worry about these changes only if you have a copy of the first nineteen printings of the book:

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
   1/22/05  tk   54   As noted above by cc about page 50, fully          1/31/05
                      constructed objects will be automatically 
                      destroyed if an exception is thrown, but this
                      guarantee applies to local (i.e., auto) objects
                      only if the exception is caught.  I added a 
                      footnote alluding to the footnote on pg. 50.

  10/27/04  ms   67   In 1st para, should also mention that a catch      1/31/05
                      clause for runtime_error can also catch 
                      underflow_error exceptions.

   9/12/04  nxd  70   In code at bottom of page, both "what" member      1/31/05
                      functions should be declared const.

   9/12/04  nxd  72   Once the decision to catch by reference has been   1/31/05
                      made, a decision must be made about whether to 
                      catch by refernce-to-const.  As always, const 
                      should be used unless the handler needs to be
                      able to modify the exception object.

 ! 8/24/04  ms   155  HeapTracked::operator delete incorrectly throws    1/31/05
                      an exception if asked to delete the null pointer.
                      It should do nothing in that case.

The following changes were made for the 21st printing. You need to worry about these changes only if you have a copy of the first 20 printings of the book:

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
   5/25/05 ir    104  The footnote incorrectly stated that both forms    7/25/05
                      of operator* on page 103 could generate the same
                      object code, but that's not true, because the top
                      implementation on page 103 (incorrectly) returns
                      a reference.  I changed the footnote wording to
                      avoid referring to example implementations on 
                      page 103.

The following changes were made for the 22nd printing. You need to worry about these changes only if you have a copy of the first 21 printings of the book:

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
   3/ 5/06 rxy   228  At top of page, ArrayIndex ==> ArraySize.          6/ 7/06

The following changes were made for the 25th printing. You need to worry about these changes only if you have a copy of the first 24 printings of the book:

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
   1/28/08 sdm   xiv  Borland is no longer Inprise.                      1/28/08

  10/24/07 sdm     8  Changed email address for book-related email to    1/28/08
                      mec++@aristeia.com.

   1/28/08 sdm   286  Replaced reference to second edition of            1/28/08
                      Effective C++ with reference to third edition.

   7/17/07 cxs   287  Removed parentheses around discussion of           1/28/08
                      Cargill's article.

   1/28/08 sdm 289-90 Added footnote on pg. 289 noting that both         1/28/08
                      magazines mentioned on this page have ceased
                      publication. (This led to a revised page break, 
                      which is why two pages are affected.)

The following changes were made for the 27th printing. You need to worry about these changes only if you have a copy of the first 26 printings of the book:

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
  10/13/09 sdm   xii  In 4th para, bad line break in the middle of      10/13/09
                      "Item 9".

  10/13/09 sdm    xv  Page layout is verso (left side) instead of       10/13/09
                      recto (right side).

   3/17/08 sdm    8,  Remove all references to the book's FTP site,     10/13/09
                287,  because the contents of that site have not been
                291,  kept up to date.  Also, all the FTPable content
                302   is (and has been) available at web sites.

  12/23/08 jxl   193  The para following the first code example says    10/13/09
                      that two lines needed to be modified, but it's
                      actually three, because the first line of the
                      member initialization list has to have a comma
                      added at the end.

   7/ 3/08 sdm   295  Remove index entries for "abstract classes,       10/13/09
                 312  and vtbls" and "vtbls, and abstract classes".

   7/ 3/08 sdm   296  Remove page 2 from index entry for "ANSI/ISO      10/13/09
                      standardization committee".

   7/ 3/08 sdm   299  Remove page 286 from index entries for            10/13/09
                 303  "design, of libraries" and
                      "libraries, design and implementation".

   7/ 3/08 sdm   303  Remove page 276 from index entry for              10/13/09 
                      "language lawyers".

   7/ 3/08 sdm   313  Index entry for "RCIPtr::CountHolder" should      10/13/09
                 316  be under "Classes and Class Templates", not 
                      "Functions and Function Templates".

   7/ 3/08 sdm   314  Remove page 200 from index entries for            10/13/09
                      "String" and "String::StringValue".

The following changes were made for the 28th printing. You need to worry about these changes only if you have a copy of the first 27 printings of the book:

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
   1/21/10 lxg   202  In code for operator=, a close curly brace        5/ 3/10
                      is missing before "return *this;".

The following changes were made for the 30th printing. You need to worry about these changes only if you have a copy of the first 29 printings of the book:

    DATE                                                                  DATE
  REPORTED WHO PAGES  WHAT                                                FIXED
  -------- --- -----  ------------------------------------------------  --------
  10/25/10 dxh   145  Specializations for both maxObjects definitions   10/18/12
                      should be preceded by "template<>".

  10/25/10 dxh   175  Specializations for SmartPtr<Cassette> and      10/18/12
                      SmartPtr<CD> should be preceded by
                      "template<>".

What follows are interesting comments about the material in More Effective C++, but I don't expect to be able to modify the book to take these comments into account until (if ever) I write a second edition.


    DATE
  REPORTED WHO PAGES  WHAT
  -------- --- -----  -----------------------------------------------------------
  11/20/97 kga        The code in the book isn't exception safe.  

                      [My reply: This is true, but the code wasn't designed to be
                      exception safe, and the material in Items 9-15
                      notwithstanding, I don't believe I ever suggested it was.

                      In 1995 (when I wrote the book), the notion of exception
                      safety was still largely unexplored.  I've written myself a
                      note to make sure that all books I write in the future
                      contain only exception-safe code, but in MEC++ (and in
                       EC++/2E), I followed the time-honored tradition of assuming
                      that exceptions never happen (hence we also never run out
                      of memory).

                      I know some will find this disappointing, but I don't think
                      this is unreasonable.  The code isn't likely to be
                      thread-safe, either.  In the future, I'll shoot for code
                      that's exception safe, but until very recently (most notably
                      the two articles by Herb Sutter in the October and
                      November/December 1997 issues of C++ Report), I don't
                      think the C++ community as a whole knew how to write
                      exception safe code.  If this shortcoming of the book
                      becomes sufficiently annoying or misleading, perhaps I'll
                      write a second edition where I can address the problem.]

  11/10/01 sdm     8  Despite untold effort, I have been unable to get Addison
                 287  Wesley to maintain the validity of their URLs, including
                      those published in my books.  The most reliable way to get 
                      to the web site for any of my publications (including More
                      Effective C++) is to go to the publications page at my web
                      site, then follow the link from there to the publication's
                      web site.  I apologize for the highly unprofessional
                      behavior on the part of the webmorons at Addison Wesley.

   2/19/96  rw    10  It's not really true that a reference MUST refer to an
                      object.  Instead, a reference is EXPECTED to refer to an
                      object (but there is no way to tell if it doesn't).
 
  12/28/97 sdm    15  An alternative way to approximate the new cast forms is to
                      use templates such as the following:

                        template<class Dest, class Source>
                        inline Dest static_cast(Source object)
                        { return (Dest) object; }
  
                      This allows clients to use the same syntax as the real
                      thing (this example is from the bottom of page 12):
 
                        double result = static_cast<double>(firstNumber)/secondNumber; 

                      This approximation calls for substantial template support,
                      however, and I'd expect any compiler supporting such
                      sophisticated templates to already offer the new cast
                      operators.

  10/20/97  nb    15  One way to get the effect of putting doSomething into an
                      array of void (*)() pointers is to write a wrapper function
                      for doSomething: 

                         void callDoSomething() { doSomething(); }
                       
                      A pointer to callDoSomething can then be safely placed in
                      funcPtrArray -- no cast is needed.

  11/ 4/97 pdb    15  The macro approximations for reinterpret_cast and
                      const_cast don't offer the same semantics as the real new
                      casts, because the approximations might take the
                      inheritance hierarchy into consideration:

                        class MI: public B1, public B2 { ... };
                        B2* b2;
                        MI* mi = reinterpret_cast(MI*, b2);
                        // ooops... mi and b2 now point at different 
                        // locations because the "normal" cast operator
                        // acts like static_cast here 

                      pdb offered the following suggested replacement
                      approximation:

                        #define reinterpret_cast(T, O) ((T)(void*)(O))
  
                      This approximation assumes that T is a pointer type,
                      however, and the new casts aren't limited to casting
                      pointers.

  12/ 5/97  rs Item 3 The best workaround for a polymorphic array is to use
                      an array of base class pointers.  In the example in this
                      Item, for example, declare printBSTArray to take an array
                      of const BST* pointers.  Provided the base class has a
                      virtual destructor, this should work fine, though you'll
                      want to be mindful of the issues discussed on page 20.

   7/13/99 sdm Item 6 For more information on prefix versus postfix versions
                      of operator++ and operator--, check out Andrew Koenig's
                      column, "Pre- or Postfix Increment" in the June 1999
                      C++ Report.

  11/24/01 iw  Item 7 As it turns out, it is possible to overload the || and &&
                      operators while still preserving their short-circuit
                      semantics, and this is not uncommon in libraries based on
                      template metaprogramming.  Because my objection to
                      overloading these operators is based on the loss of
                      short-circuit semantics, I don't oppose libraries that
                      overload them as long as they also preserve their
                      short-circuitedness.  For an example of a library that
                      overloads them for good reason, check out the Lambda Library
                      described at the Proceedings of the 2001 Workshop on C++
                      Template Programming.  (iw wasn't the only person to
                      send me the essence of this comment, but his email was the
                      one that inspired me to add it to the errata list.)

 11/ 2/07 nxd  33-34  Declaring by-value function return values const will
                      prevent their being bound to rvalue references in C++0x.
                      Because rvalue references are designed to help improve
                      the efficiency of C++ code, it's important to take
                      into account the interaction of const return values
                      and the initialization of rvalue references when
                      specifying function signatures.

   2/22/99 bm     37  "throw" cannot be overloaded.  I'm adding this as an
                      "Interesting Comment" instead of an error, because I'm not
                      convinced that "throw" is an operator.  However, bm notes
                      that "it is used the same way as delete, sizeof, or typeid
                      and the new-style casts, all of which you list as not
                      overloadable."  If somebody convinces me that "throw" is
                      an operator, I'll make this a bona fide bug report, and
                      I'll credit it to both bm and the person who convinces me
                      that "throw" is an operator.

   6/24/98 sdm Item 8 For reasons unknown to me, it has become rather uncommon to
                      speak of the "new operator" or the "delete operator".
                      Instead, one speaks of "new expressions" and "delete
                      expressions".  The C++ standard, for example, mentions new
                      and delete expressions in several places, but it never
                      really speaks of the new or delete operators.  
                          What is a new expression?  Simply an expression
                      containing a use of -- you guessed it -- the new operator.
                      Similarly, a delete expression is an expression containing
                      a use of the delete operator.  The material in the book
                      isn't incorrect, but its terminology with respect to new
                      and delete is increasingly nonstandard.  (As regards
                      operator new and operator delete, the book continues to
                      correspond to convention.  The terminology on that front
                      has been stable.)
                      
   4/30/06 txs    42  In code fragement, "freeShared(pw)" could be changed to
                      "freeShared(sharedMemory)".  It wouldn't change the
                      behavior of the code, but it's arguably better style 
                      to use the same pointer variable in the allocation and
                      deallocation calls.  In practice, of course, the
                      deallocation site may have access only to the pointer to
                      the object, so the code I show is probably typical.

  ??/??/95 bwk 49-50  Change WINDOW_HANDLE or WindowHandle to a different name so
                      they can be orally distinguished. 

   3/ 5/96  sk  50-1  Here and elsewhere the ctors (for e.g., Image, BookEntry,
                      etc.) are not declared explicit, yet Item 5 encourages its
                      use.  In fact, all constructors should be reviewed to see
                      if they should be declared explicit.  At the time I wrote
                      the book, my concern was that using explicit everywhere
                      would confuse readers, most of whom I assumed would be
                      unfamiliar with the feature.

   5/ 5/99  da  53    The following material is misleading:

                        If a destructor were invoked on an object that wasn't
                        fully constructed, how would the destructor know what to
                        do? The only way it could know would be if bits had been
                        added to each object indicating how much of the
                        constructor had been executed. Then the destructor could
                        check the bits and (maybe) figure out what actions to
                        take.

                      Notes da (David Abrahams):
  
                        Adding bits to indicate how much of the constructor had
                        been executed wouldn't be neccessary. An implementation
                        could use extra bits, but the compiler already has to
                        track similar information in order to know which local
                        (auto) objects need to be destroyed in case an exception
                        occurs. A high-quality exception-handling implementation
                        will be able to tell how much has been executed just by
                        looking at the program counter that gets pushed on the
                        stack when the function implementing "throw" in the
                        compiler's runtime library is called. There's also the
                        question, "what would it do with the information, even if
                        it were available?" Certainly, there's no way for the
                        compiler to anticipate which part(s) of the destructor
                        code might correspond to the parts of the constructor
                        that have executed...

                        ... The way we tell the compiler which parts of the
                        constructor and destructor code correspond to each other
                        is by partitioning the corresponding parts into
                        sub-objects and base classes. One easy way to do that
                        with Scott's example is to embed ImageFilePtr and
                        AudioClipPtr sub-objects in his BookEntry class, instead
                        of using pointers directly.
  
                      This final suggestion is the essence of the solution I
                      present using auto_ptrs (on page 57-58).

  10/18/99 cf   56-57 Another problem with the approach shown on these pages is
                      that it will break if we change the relative order in which 
                      the data members theImage and theAudioClip are declared.
                      The function initAudioClip is written with the assumption
                      that it will be invoked after initImage has been called,
                      but the order in which initImage and initAudioClip are
                      called is determined by the order in which theImage and
                      theAudioClip are declared in the class.  (For details on
                      the initialization order of class members, see Item 13 of
                      Effective C++.)
 
  10/26/98 sdm Item 10 Several people have suggested that function try blocks
                      should have been mentioned in MEC++, because they can be
                      used to avoid resource leaks in constructors.  As I
                      replied to one reader, 
                    
                        When I wrote MEC++, I was aware of function try blocks,
                        but I decided not to mention them, because they were so
                        new, nobody seemed to really understand how they were
                        supposed to work.  I've since resisted mentioning them,
                        because, in general, they don't solve the problem.
                      
                        Suppose a member initialization list has two different
                        initializations (as it does in on p. 56 in my book).
                        Now suppose an exception is thrown during member
                        initialization, so we end up in the catch clause of the
                        function try block.  What do we do?  We have no way of
                        knowing which initialization gave rise to the
                        exception, so we have no idea what we need to do to
                        clean up.  We can't even safely delete pointers,
                        because they may not yet have been initialized.
                    
                        My understanding is that the primary purpose of
                        function try blocks is to translate exceptions from one
                        type to another type.  This could be important if the
                        author of class C implemented C using some library L,
                        but the author of C didn't want to expose L's
                        exceptions to C's clients.

   8/14/02 sdm 66-67  The inheritance-based conversions described on these pages
                      apply only to public inheritance.  For non-public
                      inheritance, things get a bit more complicated.  For
                      details, including a rationale for the behavior, consult
                      the July 2001 column by Jim Hyslop and Herb Sutter,
                      "Baseless Exceptions."

   5/ 5/99 da Item 15 As I note in the book, there is more than one way to
                      implement the exception-handling features of C++, and
                      different compilers do things in different ways.  As a
                      broad generalization, the remarks in Item 15 show a bias
                      towards an implementation that seems to be more common
                      under Windows than under Unix.  For example, it's my
                      understanding that Visual C++ implements things in a
                      manner consistent with my description in Item 15.
                    
                      David Abrahams sent the following comments, in which he is
                      thinking of a different way of handling exceptions, a way
                      that is perhaps more popular in the world of Unix
                      compilers (though it's employed by compilers for other
                      platforms, including Windows).  Dave refers to this way as
                      "table-based", because the underlying implementation
                      involves the generation of tables of static data.  If no
                      exceptions are thrown, the data pages containing these
                      tables will never be touched.
                    
                      Here are Dave's comments:
  
                        In Item M15, Scott writes:
                        
                           Let us begin with the things you pay for even if you
                           never use any exception-handling features. You pay for
                           the space used by the data structures needed to keep
                           track of which objects are fully constructed (see Item
                           10), and you pay for the time needed to keep these
                           data structures up to date.
                      
                        In fact, a table-based implementation of exception-
                        handling will not incur any cost at runtime for updating
                        data structures. All of the neccessary information can
                        be had by looking at the program counters saved in
                        active stack frames. He goes on to say:
                      
                           These costs are typically quite modest. Nevertheless,
                           programs compiled without support for exceptions are
                           typically both faster and smaller than their
                           counterparts compiled with support for exceptions.
                        
                        Of course, these comparisons vary from implementation to
                        implementation. If you care about correctly recovering
                        from errors, it is important to only compare programs
                        compiled with EH to programs without EH support but
                        which use other error-recovery mechanisms
                        (e.g. error-return codes).
                      
                        The truth is that using a table-based EH implementation
                        can substantially improve execution speed in the usual
                        case where no errors occur, because the compiler has the
                        information it needs to move error-handling code and
                        data tables out of the cache and VM working set,
                        improving locality of reference.  Furthermore (in
                        contrast to the error-return-code approach) until an
                        error occurs, absolutely no special checks must be made.
                      
                           A second cost of exception-handling arises from try
                           blocks, and you pay it whenever you use one, i.e.,
                           whenever you decide you want to be able to catch
                           exceptions. Different compilers implement try blocks
                           in different ways, so the cost varies from compiler to
                           compiler. As a rough estimate, expect your overall
                           code size to increase by 5-10% and your runtime to go
                           up by a similar amount if you use try blocks. This
                           assumes no exceptions are thrown; what we're
                           discussing here is just the cost of having try blocks
                           in your programs.  To minimize this cost, you should
                           avoid unnecessary try blocks.
                      
                        Again, this is highly implementation-dependent. A
                        table-based implementation will not make you pay
                        anything at all in runtime for entering a try block.
                 
                      Dave has considerable expertise in the area of exception-
                      handling, and he was a significant contributor to
                      the standard library's behavioral guarantees in the presence
                      of exceptions.  In other words, he definitely knows what he
                      is talking about.
                       
                      Dave's above comments on Item 15 notwithstanding, one thing
                      on which we both agree is this advice from the end of the
                      Item: 
                       
                        If you have performance problems, profile your software to
                        determine if exception support is a contributing factor.
                        If it is, consider switching to different compilers, ones
                        that provide more efficient implementations of C++'s
                        exception-handling features.

   6/ 8/05 vxk    97  In the common case where we loop over i from 1 to n,
                      adding data at position i in each case, the algorithm as
                      shown will allocate new memory n/2 times.  It would 
                      probably be better to act more like std::vector does
                      and have the amount of new memory allocated based on
                      the current size of the DynArray instead of on how far
                      beyond the end of the DynArray the index is.

   2/21/96 sdm   101  In several places I refer to Item 6 for an explanation
                 102  of why operator+ or operator* should return a const
                 105  object instead of just an object, but Item 6 discusses
                 107  only operators ++ and --.  The problem is that without
                      a const return value, things like this become possible:
                      
                        (a + b) = 14;  // assign to the object returned
                        (a * b) = 0;   // from the operator!
                        
                      Such assignments are incompatible with the behavior of the
                      built-ins and are also typically nonsensical, so they
                      should generally be prohibited.  Returning const objects
                      prohibits them, just like it prohibits expressions like
                      "i++++" (which is discussed in Item 6).  (It's possible to
                      get around the prohibition by declaring operator= to be a
                      const member function, but that notion opens doors I
                      prefer to leave both closed and locked.)
                       
   1/20/11 jxw   104  The fact that compilers are permitted to optimize
                      temporary objects out of existence means that observable
                      side effects that would take place during their
                      construction and destruction may not occur.

   2/27/01 ph Item 20 Writes ph:
 
                        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.
                       
                        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.

   9/23/01 lz Item 21 One drawback to lots of overloading is that it can lead to
                      ambiguities.  For example, if you declare both f(int) and
                      f(long) and a client calls f with a char or a double, the
                      call will be ambiguous until the client casts the char or
                      double to an int or long.

   2/12/07 axj Item 21 In practice, the operator+ functions discussed in this
                      Item would often need to be friends of UPInt or would 
                      have to call friends of UPInt in order to have direct or
                      indirect access to UPInt's (private) data members.

   5/14/00 rz  Item 22 Rather than try to summarize rz's points, I'm just
                      going to quote his mail to me:

                        When considering op vs. op=, there's more to consider
                        than consistency and efficiency (return value
                        optimization -- RVO). Whether or not an operation is
                        affected by aliasing must also be considered.
                      
                        Consider matrix multiplication:
                      
                          Matrix& Matrix::operator *=(const Matrix& rhs)
                          {
                            // lhs is both input and output!
                            Matrix result;
                            for (int i = 0; i < size; ++i)
                            {
                              for (int j = 0; j < size; ++j)
                              {
                                result[i, j] = 0;
                                for (int k = 0; k < size; ++k)
                                  result[i, j] += (*this)[i, k] * rhs[k, j];
                              }
                            }
                            (*this) = result;
                          }
                      
                        Because "this" is used for both input and output (and
                        because matrix multiplication requires many input
                        elements to calculate a single output element), it is
                        necessary construct the result in a (named) temporary to
                        avoid problems with aliasing.
                      
                        In this case, * is actually simpler than *=. operator*
                        involves merely constructing a result (as opposed to
                        reassigning the result to an existing object). A better
                        implementation of both * and *= is:
                       
                          Matrix operator *(const Matrix& lhs, const Matrix& rhs)
                          {
                            Matrix result;   // set up RVO
                            for (int i = 0; i < size; ++i)
                            {
                              for (int j = 0; j < size; ++j)
                              {
                                result[i, j] = 0;
                                for (int k = 0; k < size; ++k)
                                  result[i, j] += lhs[i, k] * rhs[k, j];
                              }
                            }
                            return result;   // hope for RVO
                          }
                      
                          Matrix& Matrix:operator *=(const Matrix& rhs)
                          {
                            Matrix result = (*this) * rhs;
                            return *this = result;
                          }
                      
                        If a compiler applies RVO and eliminates the unnecessary
                        temporary in the construction of the result in *=, this
                        latter implementation is close to optimal and achieves
                        consistency between * and *=.
                      
                        If an efficient swap function is defined, we can avoid
                        the cost of assignment from the result to "this":
                      
                          Matrix& Matrix:operator *=(const Matrix& rhs)
                          {
                            Matrix result = (*this) * rhs;
                            swap(result);
                            return *this;
                          }
                      
                        The definition of op= in terms of op using the idiom
                        above makes sense when aliasing is an issue.
                      
                        In contrast, aliasing is not an issue for matrix
                        addition. Thus we can define + in terms of +=, as you
                        suggest in MEC++ Item 22:
                      
                          Matrix& Matrix::operator +=(const Matrix& rhs)
                          {
                            for (int i = 0; i < size; ++i)
                              for (int j = 0; j < size; ++j)
                                (*this)[i, j] += rhs[i, j];
                          }
                      
                          Matrix operator +(const Matrix& lhs, const Matrix& rhs)
                          {
                            Matrix result(lhs);   // set up RVO
                            result += rhs;
                            return result;        // hope for RVO
                          }
                      
                        Note that all of these implementations should be
                        exception-safe (as operator =): Only after calculations
                        are successfully completed in temporaries is the result
                        assigned to "this".

   1/ 4/97  ih   108  The template functions for operator+ and operator- don't
                      behave exactly like hand-written versions of the same
                      functions, because the rules for resolving calls to
                      overloaded functions allow slightly different sets of
                      implicit conversions when calling template and non-template
                      functions. 

 !11/23/99 jm2   109  Both the first and second implementations on this page
                      suffer from the problem that they are returning whatever
                      operator=+ returns.  In general, there is no way to know
                      what this is (yes, it's a reference to an object of type T,
                      but a reference to which T object?), hence no way for
                      compilers to optimize away the copy to operator+'s return
                      value.  The way to write operator+ such that the return
                      value optimization can be performed is with this body:
             
                        T result(lhs);
                        result += rhs;
                        return result.

   9/15/99 sdm   111  A few people have pointed out that in the C++ code on this
                      page, it's possible to pull the calls to setprecision and
                      setiosflags out of the loop, and this might make the C++
                      code faster.  I deliberately left these calls in the loop,
                      because the corresponding C code has to set up the
                      formatting each time printf is called.  To be fair, I
                      wanted C++ to have to do the same.
 
   8/10/06 jxb   112  jxx writes: "I have performed comparsions of iostream vs
                      stdio on GCC3, GCC4 and ICC and I found that, while on GCC3
                      the difference was significant in favor of stdio, on GCC4
                      and ICC they performed exactly the same.  (For every test I
                      made, I was compiling with full optimizations on.)"

  12/15/97 sdm Item 26 For a more complete discussion of how to count the number
                      of objects in existence, see my article, "Counting Objects
                      in C++," in the April 1998 Dr. Dobb's Journal.

  12/31/97 sdm 130ff  The technique of returning a reference to a static object
                      inside a function isn't thread-safe.  If thread-safety is
                      important to you, you're better off using a variant on the
                      GOF Singleton technique, though you must then confront the
                      problem of how to get rid of the Singleton.  For further
                      discussion of the issue of thread safety, consult 
                      Doug Schmidt's papers on the topic. For more on the problem
                      of destroying a Singleton, check out John Vlissides'
                      column, "To Kill A Singleton," in the June 1996 issue of
                      C++ Report (and since reprinted in Vlissides' book,
                      Pattern Hatching).

  12/ 3/05 txs 138-140 The Printer destructor code on page 135 should be repeated
                      at least once somewhere in this page range to remind readers
                      of what happens in the destructor.

   9/27/99 jb 141-145 The Counted template could take a second argument for the
                      maximum number of objects to create: 

                        template<typename BeingCounted, size_t maxObjects>
                        class Counted { ... };

                      Printer would then specify the value of maxObjects in its
                      class definition:

                        class Printer: private Counted<Printer, 10> 
                        { ... };

                      This way, there'd be no need to remember to define and
                      initialize Counted<Printer>::maxObjects (as discussed on
                      pages 144-145).  On the other hand, this would move the
                      value of maxObjects from a .cpp file to a .h file, and that
                      might not be desireable.

  12/ 4/99 ag  145-6  Declaring the class destructor private also makes it
                      impossible to use auto_ptr (or most other smart pointers)
                      with heap-allocated objects of the class.  A preferable
                      alternative may be to declare all the constructors
                      private.  

  10/25/10 dxh 145-6  In the same way that declaring the destructor private
                      necessitates the declaration of some kind of public
                      pseudo-destructor, declaring all contructors private
                      would necessitate the declaration of some kind of public
                      pseudo-constructors. 

   4/17/99 sdm Item 27 Over the years, the issue of determining whether an object
                      is on the heap has attracted a lot of interest, and I've
                      received numerous messages about it.  I've thus set up a 
                      web page with an extensive discussion of the matter, 
                      including several alternatives to the approach I develop
                      in the book. 

  12/10/98 jed   154  It's dangerous to make HeapTracked::addresses static,
                      because there is no guarantee that that object will be
                      initialized before it's used.  The full story is told in
                      Item 47 of Effective C++, but I fail to describe it in this
                      book (primarily because I treat it in Effective
                      C++).  A reasonable solution to the problem is to
                      create a private static member function, addresses(), that
                      returns a reference to a list<RawAddress> object that's
                      static inside the function.  This is essentially what I do
                      with the map inside SpaceShip on pages 238ff; note how the
                      map is made static inside SpaceShip::lookup.

   7/18/09 fxb 154-5  Because addresses is static inside HeaptTracked, all
                      allocated addresses go into a single list.  An alternative
                      would be to make HeapTracked a template that's templatized
                      on the class inheriting from it:

                        template <typename DerivedClass>
                        class HeapTracked { ... };

                      (This is similar to the design I use for counting
                      objects on pp. 141ff.)

   7/18/09 fxb 154-5  Rather than use a list for addresses, it might be
                      preferable to use a set.  The current design adds
                      addresses in constant time, but removes them only in
                      linear time.  Use of a set would have both operations run
                      in logarithmic time.

   4/ 6/96 edw   157  Declaring class-specific operator new private doesn't
                      totally prevent heap-based objects, because it's still
                      legal to create them via ::new.

   7/20/96 os 175-179 The member template for implicit conversions works, but it
                      creates a temporary return object from a dumb pointer each
                      time a conversion is performed.  This is inappropriate for
                      the reference-counting smart pointers of Item 29, because
                      the temporary would create a new value object instead of
                      sharing an existing value object.  Supporting
                      inheritance-based conversions for Item 29's smart pointers
                      requires nontrivial changes to the designs in Item 29.
                      
  12/ 7/97 sdm 168-70 To allow smart pointers to be tested for nullness,  I'm
                      increasingly fond of the technique Don Box described in
                      his March 1996 C++ Report column: have smart pointer
                      classes support implicit conversion to a nested class
                      type:

                        template<class T>
                        class SmartPtr {
                        public:
                          struct NestedClass{};       // empty nested class
                          ...
                          operator NestedClass*() { return ptr; }
                      
                        private:
                          T *ptr;
                        };
                    
                        SmartPtr<Widget> sp = new Widget;
                        ...
                        if (sp) ...  // convert to SmartPtr<Widget>::NestedClass*
                        ..
                        if (sp == NULL) ...      // do same conversion as above

 !12/11/06 jvdb 175-178 The type conversion code yields multiple smart pointers
                      to the same underlying object, but it fails to address
                      the problem of ownership that is raised on pp. 162ff.  It
                      should. (auto_ptr is designed to transfer ownership to
                      the auto_ptr created by the conversion function, but, as 
                      noted in a defect report to the standardization committee,
                      the design is flawed.)

   4/ 6/96 edw   181  Because SmartPtrToConst is a concrete base class, we can
                      still run into the assignment-related problems described in
                      Item 33.  For example, if SmartPtr performs a deep copy in
                      its assignment operator but SmartPtrToConst does not, an
                      assignment to a non-const object through a SmartPtrToConst
                      pointer would fail to perform the deep copy. 

  11/10/96  tb 181-2  The inheritance-based design allows a SmartPtrToConst<T>&
                      to be initialized with a SmartPtr<T> object.  This is
                      unsafe (it allows const objects to be modified when they
                      should not be), and the dumb pointer analogue --
                      initializing a const T*& with a T* -- is prohibited by C++. 
  
   2/ 7/96 tu Item 28 The use of member function templates to implement smart
                      pointer type conversions is problematic in the presence of
                      object ownership, because the ownership must be transferred
                      to the temporary object created as a result of the
                      conversion.  This is essentially the same as the auto_ptr
                      problem I describe in the book on p. 164. 

   2/12/96 wrz 190-3  The shareable flag solves one side of this problem, but the
                      flip side remains unsolved: how to guarantee that the
                      reference handed out by the non-const operator[] remains
                      valid for the life of the String object. Consider:
                      
                        String s1 = "Hello";
                        String s2 = "Goodbye";
                        char *p = &s1[2];
                        s1 = s2;   // this invalidates p, because it still points
                                   // into the memory owned by the StringValue
                                   // that s1 USED to point to, sigh
                                     
                      The solution to this problem entails finding a way to make
                      sure that s1 never points to a different StringValue object
                      once a reference has been returned.  (This is essentially
                      the problem that Tom Cargill attacks in his June 1992
                      C++ Report article, sigh.) This is, in general, a very hard
                      problem.  The ISO/ANSI string class deals with it by saying
                      that any reference returned from operator[] becomes invalid
                      the next time a non-const member function is invoked on the
                      string object. 
 
   6/ 3/03 sxb   202  The bug for these pages reported by ct on 9/16/98 is
                 206  incorrect, because when RCPTR::operator= is called with
                      a raw pointer as an argument (e.g., p->next), a
                      temporary RCPtr will be created from the raw pointer, hence
                      the reference count won't go to 0 when removeReference is
                      called.  (I'll keep the code in the book as is, because it
                      behaves correctly, and I don't want to mess with code in
                      the book any more often than I have to.)

   7/ 5/96 os 208-210 Because CountHolder is nested inside RCIPtr<T>, it is not
                      possible for an RCIPtr<Base> and an RCIPtr<Derived> to
                      point to the same CountHolder, even though they should be
                      type-compatible.  Not even the techniques of Item 28 (i.e.,
                      member templates to simulate inheritance for smart pointers)
                      solve the problem.  A better design is needed, probably one
                      based on CountHolder being a template class at global scope
                      (like RCPtr). 

   5/ 5/99 da 208ff   As noted above, the code in the book wasn't generally
                      designed to be exception-safe, but it's still worth noting
                      that RCIPtr is likely to lead to resource leaks in the case
                      of an exception.  For example:

                        template<class T>
                        RCIPtr<T>::RCIPtr(T* realPtr)
                        : counter(new CountHolder)
                        { ... }
                    
                      If "new CountHolder" throws an exception, it's probable
                      that the realPtr parameter will be leaked.  Here's a fix:
                  
                        template<class T>
                        RCIPtr<T>::RCIPtr(T* realPtr)
                        {
                          try { 
                            counter = new CountHolder; 
                          }
                          catch(...) {
                            delete realPtr;
                            throw;
                          }
                    
                          ...
                        }
 
   1/18/97 sdm Item 29 Because RCObject has a virtual destructor, any class
                      inheriting from it will have a vptr (see Item 24).  Some
                      classes won't like this extra baggage.  RCObject can be
                      redesigned to have a nonvirtual destructor, but then
                      removeReference can't "delete this" when the reference
                      count is 0.  Instead, isShared must be replaced with a
                      function to return the current reference count, and anybody
                      calling removeReference (e.g., operator= and the destructor
                      in RCPtr<T>) must then check to see if the result is
                      0.  If so, they must delete the RCObject.  Finally, each
                      value class should privately inherit from RCObject to make
                      the nonvirtual destructor a valid design.  This revised
                      design imposes no overhead on classes inheriting from
                      RCObject, but the deletion burden when the reference count
                      goes to 0 is shifted from RCObject to all its clients.

   5/ 7/99 vp Item 29 Writes vp: "The RCIPtr class also reference counts null
                      pointers. If I want to use a vector of RCIPtrs and I
                      initialize the vector as vector< RCIPtr<T> > vec(1000),
                      this would create 1000 countholder objects, all of which
                      would point to NULL. Would it not be better to not
                      reference count the null pointer by not creating
                      countholder objects when the RCIPtr contructor is invoked
                      with a null pointer and then using the check "if (counter)"
                      whereever necessary?"
                        My reply is that whether that's better depends on how
                      frequently you expect to deal with null pointers.  If you
                      expect null pointers to be a relative rarity, the runtime
                      friction of the nullness tests might be something you'd
                      prefer to avoid.  If you expect to deal with null pointers
                      relatively frequently (as the example above suggests), vp's
                      design might be preferable.  I've seen smart pointers
                      designed both ways.

   4/27/97 sdm Item 30 In a posting to comp.lang.c++.moderated posting of
                      4/25/97, Brian Parker writes:

                        One problem with the use of proxies that I have found that
                        is not discussed in "More Effective C++" is when they are
                        used for templated types e.g. for complex <double>... .  In
                        this scenario, when calling template functions that take
                        complex<T> (e.g. conj() et al) with a returned proxy, the
                        proxy is not converted to a complex<double> but instead a
                        template argument deduction failure results.
  
                      For further information on this observation, look up the
                      thread, "lvalue/rvalue, non-const/const" initiated by Daniel
                      Hempel on April 21, 1997.

   1/26/06 sdm Item 30 Sander Stoks wrote an interesting article ("Syntactic
                      Aspartame:  Recreational Operator Overloading") exploring
                      some, er, innovative applications involving proxy
                      classes in the Feburary 2006 Dr. Dobb's Journal.

   7/25/09 fxb 219ff  There is little to be gained by having the const
                      String::operator[] return a proxy.  One might as well
                      retain the declaration for that function shown on page 218.

   9/ 5/99 ll    221  As I should have suspected, the const_cast leads to
                      trouble.  Consider: 

                        const String& str;
                        String::CharProxy cp = str[0];
                        cp = 'x';                      // modify const string!
  
                      Of course, clients aren't supposed to create local
                      variables of type String::CharProxy, but if it compiles,
                      somebody will do it.  Sigh.  The solution is to have two
                      different proxy classes, one for const objects (e.g.,
                      ConstCharProxy) and one for non-const objects (the current
                      CharProxy).  ConstCharProxy would be almost identical to
                      CharProxy, but it wouldn't support assignment or any other
                      lvalue use.  Such a design would probably requiring
                      tinkering in many places, e.g., CharProxy would have to be
                      able to be the target of an assignment from a
                      ConstCharProxy.
                        The real moral of the story here is one I should have
                      learned by now: casts are almost always bad!

   3/21/96  jj   223  Instead of having both String::CharProxy operator=
                      functions call a common private function, it would be
                      better to make the const CharProxy& version just call the
                      char version.  That way there'd be no need for an
                      additional private member function:

                        String::CharProxy& 
                        String::CharProxy::operator=(const CharProxy& rhs)
                        { 
                          *this = rhs.operator char();   // call operator=(char)
                          return *this;
                        }
						
   6/26/98 sdm   226  One way to make all operations on a T applicable to a proxy
                      for a T is to have Proxy <T> inherit from T.  This is the
                      design advocated in the Proxy Pattern in the book, 
                      Design Patterns, by Gamma, Helm, Johnson, and Vlissides.
                      Unfortunately, this works only when T can be inherited
                      from, and that's not the case when T is char (as it is in
                      Item 30).

   4/ 2/96 rv Item 31 When setting up collision maps, it would be safer to avoid
  10/19/97 mr         the use of literal strings like "SpaceShip".  Instead, the
  11/23/99 wek        maps should be initialized via calls to typeid.  That way it
                      would be harder to accidently use the wrong string for a
                      class name.  Furthermore, the standard makes it clear
                      that type_info::name can return just about anything, so
                      there's no portable use for the results of that function.
                      That suggests that the map-related typedefs for the
                      non-member solution of pp. 244-248 should really be these:
                        typedef void (*HitFunctionPtr)(GameObject&, GameObject&);
                        typedef map<pair<const type_info*, const type_info*>,
                                    HitFunctionPtr> HitMap;
                      That's not quite right, however, because the map's
                      ordering function would be 
                      less<pair<const type_info*, const type_info*> >,
                      and there's no guarantee that that will (1) exist and
                      (2) behave in a reasonable fashion.  Furthermore,
                      you're not allowed to define your own version of this
                      class, because it doesn't use any user-defined types.
                      You'd therefore have to write a custom comparison class
                      for the map:
                        class TICompare { ... };   // "type_info compare"
                        typedef void (*HitFunctionPtr)(GameObject&amp;, GameObject&amp;);
                        typedef map<pair<const type_info*, const type_info*>,
                                    HitFunctionPtr, TICompare> HitMap;
                      Details are left to the reader, but inside TICompare's
                      operator()(), it would be important to use
                      type_info::before() instead of comparing raw type_info*
                      pointers, because the results of comparing raw pointers
                      is generally undefined.
  
   2/22/99 bm Item 31 The function makeStringPair is no longer needed, because
                      the make_pair function (briefly described on page 247) is
                      more flexible in the final standard than it was in the
                      draft standard I consulted when I wrote the book.  When I
                      wrote the book, make_pair<T1,T2> could only create an
                      object of type pair<T1,T2>, but now make_pair<T1,T2> can
                      create an object of type pair<T3,T4> as long as T1 is
                      implicitly converible to T3 and T2 is implicitly
                      convertible to T4.  Because const char* is implicitly
                      convertible to string, make_pair<const char*, const char*>
                      can be used to create an object of type pair<string,
                      string>.  The code in the book isn't wrong, it's just
                      unnecessarily complicated.  (The code in the book is also
                      more portable, because it doesn't rely on compiler support
                      for member function templates.  The new, simpler approach
                      does.)

   4/26/99 bs Item 31 In cases where symmetry applies (e.g., where the results of
                      processCollision(A, B) are the same as the results of
                      processCollision(B, A)), it may be preferable to store a
                      function pointer in the map for only one of the
                      combinations, then look up the second one if the first one
                      fails, i.e., do lookp(A,B) and, if it fails, do
                      lookup(B,A).  Only if both fail would 0 be returned.  As
                      Bram notes, "It would make it more difficult for the map to
                      get in a corrupted state.  The loss in performance is
                      moderate, and can be compensated by using hash_map instead
                      of std::map."  (hash_map is not standard, but many versions
                      of the STL include it.)

   6/30/99 pab p239ff If an exception is thrown within initializeCollisionMap,
                      the resources acquired by the map will be leaked.  A better
                      design would be to use an auto_ptr<HitMap> both inside
                      initializeCollisionMap and as its return type, like this:
  
                        auto_ptr<HitMap> initializeCollisionMap()
                        {
                           auto_ptr<HitMap> phm(new HitMap);
                           ...
                           return phm;
                        }

                      This is definitely a superior design, but please keep in
                      mind my comments above on exception safety in reply to
                      kga's observation of 11/20/97.

   1/ 9/00 sdm Item 31 On 11/16/99, Edmund Schweppe initiated a thread in the
                      newsgroup comp.lang.c++.moderated with the subject,
                      "Multiple Dispatch -- Better Than Item 31?"  As of
                      1/9/00, there were nearly 100 articles in the thread;
                      I contributed a few of them.  On 1/6/00, Rob Santos
                      initiated a similar thread, "Better than item 31."  If
                      you're interested in multiple disptach, I encourage
                      you to read these threads.  

   8/ 5/01 sdm Item 31  For a more contemporary treatment of multiple dispatch
                      than I give in Item 31, check out chapter 11 of Andrei
                      Alexandrescu's excellent Modern C++ Design. 

  12/18/03 sdm Item 31 Nat Goodspeed's article, "Double Dispatch Revisited,"
                      contributes an interesting new approach to implementing 
                      support for double dispatch that also supports
                      inheritance.

   3/11/08 sdm Item 31 Over a decade after MEC++ was published, interest in
                      double-dispatching (including the closely-related
                      Visitor design pattern) remains high.  One recent
                      treatment is Danil Shopyrin's "MultiMethods in C++:
                      Finding a Complete Solution," which is presumbably the same
                      technique described in Shopyrin's article,
                      "Multimethods in C++ Using Recursive Deferred
                      Dispatching," in the May/June 2006 issue of
                      IEEE Software.  Another is Anand Shankar Krishnamoorthi's
                      "Cooperative Visitor: A Template Technique for Visitor Creation."
                      (As with all online articles, be sure to check the
                      accompanying online discussions and comments, because they
                      often provide clarifications and insights missing from the
                      articles themselves.)

   7/31/98 sdm Item 33 Note that prior to the transformation, it's legal and
                      sensible to assign a Lizard or a Chicken to an
                      Animal.  After the transformation, it's not.
 
  10/20/97  nb 269-70 Another possible workaround for inheriting from concrete
                      classes in read-only libraries is to create a new abstract
                      class inheriting from the concrete class, then have your new
                      concrete class inherit from the abstract class so derived.

   6/26/98 sdm 269-70 At the end of the third bulleted paragraph, note that the
   5/ 5/99            use of private inheritance models "is-implemented-in-terms-
                      of" and DOES allow for virtual functions to be redefined.
                      See also Herb Sutter's column in the October 1998 
                      C++ Report, which discusses the private inheritance
                      solution and also shows how to combine inheritance and
                      composition such that it's possible to override the virtual
                      functions in a base class WITHOUT inheriting from it.

 !10/10/01 pb    272  Notes pb, "'extern "C"' doesn't mean that name mangling is
                      suppressed. Rather, it means that names should be mangled in
                      the way that the targeted C compiler mangles them. Some C
                      compilers put an underscore at the front of a name; others
                      put an underscore at the end; some don't change the name at
                      all. A name declared as 'extern "C"' should be mangled in
                      the same way."

   5/ 5/02 ar  272-3  extern "C" and extern "C++" are actually different types,
                      making something like this illegal:
  
                        extern int foo(double d);
                        extern "C" int bar(double d);
                     
                        int (*ifp)(double d) = foo;	/* OK */
                        int (*ifp)(double d) = bar;	/* type mismatch */

                      I.e., assigning an extern "C" function to a pointer to
                      a C++ function isn't allowed.  Most compilers fail to
                      enforce this restriction.  (BTW, the Standard supports
                      both extern "C" and extern "C++".  There is little use
                      for the latter, as it is the default language linkage.)

   8/28/98  dp   274  Static objects must be destroyed even if exit is called
                      (instead of running off the end of main).  The call to
                      performStaticDestruction should really go inside exit(),
                      and that's where compilers employing this scheme actually
                      put it.

   1/18/04 sdm Item 34 A topic related to this Item is how to link object code
                      generated from different C++ compilers.  For one take on
                      that topic, consult Karsten Hoof's February 2004
                      CUJ article, "GNU & Native Compilers."  For another,
                      see Joe Goodman's March 2004 CUJ article,
                      "Interoperability & C++ Compilers."

 !11/ 2/00 sdm  291ff Copy constructor and assignment operator are missing and
                      won't be generated from the template member functions.
                      These need to be added elsewhere in the book, too.

Who's who:

  lsk  = Luis Sergio Kida                  avk  = Andrew V. Klein          
  jep  = John E. Potter                    en   = Eric Nagler              
  tu   = Tim Uttormark                     js   = Jeffrey Smith            
  msf  = Mike Fulkerson                    sb   = Sam Bent                 
  ds   = Dan Saks                          ahd  = Anton Doblmaier          
  wg   = Wolfgang Glunz                    os   = Oleg Shteynbuk           
  wrz  = Warren R. Zeigler                 um   = Ulf Michaelis            
  clt  = Clovis L. Tondo                   sm   = Sekhar Muddana           
  rw   = Rob Wilkinson                     mb   = Michael F. Baker         
  ml   = Michael Loftus                    ymk  = Yechiel M. Kimchi        
  lh   = Liz Hanks                         dmp  = David Papurt             
  sk   = Stefan Kuhlins                    ih   = Ian Haggard              
  jm   = Jim McCracken                     ras  = Robert Allan Schwartz    
  we   = Wil Evers                         tb   = Thomas Becker            
  jj   = John Jacobsma                     jl   = Jon Lachelt              
  aid  = Alan I. Duchan                    dh   = David Halpin             
  rcn  = Ramesh Nagabushnam                mr   = Mark Rodgers             
  rv   = Roger Vaughn                      nb   = Nick Bishop              
  tjb  = Timothy John Buchowski            clf  = Cheryl L. Ferguson       
  ks   = Kirk Swenson                      mm   = Munir Mahmood            
  edw  = Ed Willink                        gm   = Graham Mark    
  psrc = Paul S R Chisholm                 dab  = David A. Barrett 
  jr   = Jack Reeves                       drk  = Damian R. Kanarek
  dcs  = Douglas C. Schmidt                rxc  = Ron Coutts 
  lw   = Lance Whitesel                    pdb  = Paul Du Bois            
  kga  = Klaus-Georg Adams                 rs   = Rao Surapaneni          
  cxm  = Chris Morley                      dxg  = David Goh    
  rxb  = Rainer Baumschlager               jed  = James Davis  
  cwg  = Charles W. Green                  bwk  = Brian Kernighan       
   dp  = David Petrou                      jww  = John Wait
  rhs  = Bobby Schmidt                     bm   = Bernd Mohr              
  jsh  = Sivaramakrishnan J.               da   = David Abrahams          
  ea   = Eric Anderson                     pab  = Phil Brabbin            
  bs   = Bram Stolk                        jb   = Jaroslav Bradik         
  vp   = Vasanth Philomin                  wek  = William Kempf           
  ll   = Lou Lavery                        km   = Kurt Miller             
  fk   = Feliks Kluzniak                   jm2  = Jörg Barfurth           
  ct   = Christopher Tavares               js2  = Julian Smith            
  ag   = Andy Glew                         rz   = Rob Zako                
  cf   = Carsten Frigaard                  ccr  = Christopher Creutzi     
  em   = Evan McLean                       wcm  = William C. Mattison     
  nxd  = Niels Dekker                      bp   = Balog Pal               
  ac   = Alexsander Chukhlebov             cw   = Chris Wineinger         
  wds  = Dean Stanton                      csp  = Chulsu Park             
  ph   = P. Haution                        ga   = Giulio Agostini         
  pb   = Pete Becker                       agb  = Alexander Bogdanchikov  
  jfn  = John Newell                       ar   = Aharon Robbins          
  lz   = Leor Zolman                       mt   = Michael Tegtmeyer       
  pd   = Pankaj Datta                      ais  = Adrian Spermezan        
  iw   = Ian Whittley                      ddg  = Davide D. Gennaro       
  at   = Ani Taggu                         cc   = Chang Chen         
  mh   = Matthias Hofmann                  jw   = John Wismar        
  ms   = Mark Symonds                      ir   = Ita Ryan     
  fb   = Fredrik Blomqvist                 vxk  = Vassili Kaplan 
  tk   = Thomas Kim                        txs  = Thomas Schell
  rxy  = Rice Yeh                          jxb  = Jan Bujak
  axj  = Arun Joseph                       jvdb = Jelle van der Beek
  cxs  = Colas Schretter                   jxl  = Johannes Laire
  fxb  = Florian Bauer                     lxg  = Leonhard Gruenschloss 
  dxh  = Dongbo Hu                         jxw  = Jonathan Wheeler 

From here you may wish to visit the Amazon Page for More Effective C++.