Scott Meyers
Modification History and Errata List for Effective STL
Last Updated 2 October 2018
by Scott Meyers
What follows are my notes on what I've changed in Effective STL 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 represent important technical modifications, I precede those entries with an exclamation mark ("!") and display them in red.
Each entry includes the following information:
- Date Reported: The date the problem was brought to my attention.
- Who: The initials of the person reporting the problem. The initials "sdm" refer to me. The mapping from other initials to full names is at the bottom of this document.
- Pages: The pages of the book (or the Item number) affected.
- What: A description of the problem and the solution.
- Date Fixed: The date on which I fixed the problem. If no date is shown, it means I haven't gotten around to fixing the bug or I'm still mulling over whether I want to fix it. Sometimes I change my mind on bug reports, so prospective bugs often spend quite a while in the "not yet fixed" state. When Addison-Wesley notifies me that a new printing is about to take place, I go through the bugs and fix all those I've decided must be fixed. It's thus not uncommon for all the bugs fixed for a particular printing to have the same fix date.
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 Effective STL. To submit comments, send email to estl@aristeia.com.
To be assured of always having the most accurate version of Effective STL at your fingertips, I encourage you to buy a copy of each printing :-).
The following changes were made for the second printing of the book. You need to worry about these changes only if you have a copy of the first printing of Effective STL:
DATE DATE REPORTED WHO PAGES WHAT FIXED -------- --- ----- ------------------------------------------------ -------- 6/27/01 js 95 In second comment on page, "mulitmap" ==> 6/27/01 "multimap" 6/21/01 jw 136 In the last comment in the code example, 6/27/01 "goalPosition now points" ==> "begin + goalOffset now points" 6/26/01 mjh 164 "containing lot of data" ==> "containing lots 6/27/01 of data" 5/ 7/01 sdm 228 Add to [26] that the article and the software it 6/27/01 describes can be downloaded from http://www.bdsoft.com/tools/stlfilt.html. 6/26/01 dp 228 URLs for both columns by Matt Austern ([24] and 6/27/01 the second bullet after [27]) end in .htm, not .html. (I checked all the URLs shortly before publication, so these must have changed right after the book was initially printed.)
The following changes were made for the third printing of the book. These changes apply to your copy of Effective STL only if it's the first or second printing.
DATE DATE REPORTED WHO PAGES WHAT FIXED -------- --- ----- ------------------------------------------------ -------- 7/21/01 sdm Inside Diagrams should indicate which Items they are 10/30/01 Cover from. Inside front cover is from Item 45. Inside back cover is from Item 15. 8/31/01 ds iv "Dr. Suess" ==> "Dr. Seuss" (twice). (By AW) 9/ 4/01 bww iv Change "Meyer, Scott" to "Meyers, Scott" in the (By AW) Library of Congress Cataloging-in-Publication Data. 7/16/01 hh 11 In 2nd para on page, "pointers of auto_ptrs" ==> 10/29/01 "pointers or auto_ptrs" 8/ 4/01 dg 18-19 Once the typedef WidgetContainer is introduced, 10/29/01 the variable vw should be renamed cw to reflect the new, more abstract, type name. 8/23/01 sdm 23-24 Clarify that only one of the three list::splice 10/29/01 functions requires linear complexity. The other two can run in constant time and can allow size to run in constant time. 10/29/01 sdm 23 Twice on this page, "list" is in the wrong font. 10/29/01 ! 7/13/01 pc 27 In the second code example, insertLoc needs to 10/29/01 be incremented after the call to insert. This error is especially embarrassing, because I got it right on pp. 184-5 (where I also explain what happens if you don't do the increment). 7/27/01 ras 34 In first bullet para, "It's type" ==> "Its type" 10/29/01 6/29/01 sdm 47 In the last line of paragraph 2, "list" should 10/29/01 be in code font. 8/17/01 sdm 47 Omit from para 2 the advice to treat list like 10/29/01 a sequence container. Based on a discussion with jep, I'm now less certain that that convention is as widespread as I'd thought. 10/ 4/01 ap 47 In 1st para, clarify that erase's return value 10/29/01 is void in associative containers only for the forms taking iterators. (When passed a value, erase returns the number of elements erased.) 7/13/01 gk 57 Near middle of page, "Then you use 10/29/01 SpecialHeapAllocator" ==> "then you use SpecificHeapAllocator" 7/28/01 jep 59 In 1st para, "be convenient state" ==> 10/29/01 "be a convenient state". 10/24/01 wg 66 The first sentence of the third paragraph 10/29/01 begins, "Given all that ..., It should not". The word "it" is errantly capitalized. 10/11/01 gn 67 In second and third bullets, the parameters 10/29/01 taken by resize and reserve are of type Container::size_type, not size_t (though for all the standard containers, Container::size_type must be size_t). 7/21/01 tm 75 In 2nd para, "stored in contiguous memory" ==> 10/29/01 "stored in a single chunk of contiguous memory" 7/23/01 jeh 76 In the last line of the comments above the 10/29/01 declarations for fillArray and fillString, change "maxNumDoubles" or "maxNumChars" to "arraySize". ! 8/23/01 ja 79 The last paragraph of Item 17 is incorrect. 10/29/01 5/23/02 en string is unique among the standard containers in having swap invalidate all pointers, references, and iterators into the strings. (Such swaps do not invalidate anything when done to vectors, deques, lists, or any of the standard associative containers.) Omit paragraph. ! 8/22/01 sdm 92 Eliminate the second-to-last sentence on this 10/29/01 250 page. In fact, equal values are equivalent, because neither of two equal values precedes the other in any reasonable sort order. (The definition of "reasonable" is "strict weak ordering," as I mention on page 94.) Page 250 was changed to eliminate the index entry for "equality, implying inequivalence". !10/11/01 gn 99 In the long middle para, casting away the 10/29/01 constness of a map key doesn't yield undefined behavior, but attempting to modify the key does. 7/ 8/01 dm 100 The order of steps 3 and 4 should be reversed, 10/29/01 both at the top of the page and in the code example. This improves the exception safety of the approach. 8/22/01 jep 100 Step 5 says that giving an accurate hint to 10/29/01 6 insert yields constant-time complexity, but it 246 actually yields amortized constant time 247 complexity. When I fixed this, I added a 248 definition of "amortized constant time" to page 6, plus I added related index entries. ! 8/22/01 jep 104 In the lines after the calls to lower_bound, the 10/29/01 106 second test should be "!(w < *i)" and "!(s < i->first)", respectively. This needs to be fixed in both the code and the comments. 8/22/01 jep 104 In the comments following the calls to 10/29/01 106 lower_bound, the reference to Item 45 should be to Item 19. 7/ 1/01 cm 105 In second-to-last para, "consistency between" 10/29/01 ==> "consistency among" 8/22/01 jep 110 As in jep's bug report for page 100 above, 10/29/01 insertion with a hint yields amortized constant time complexity, not simply constant time. 7/23/01 jeh 114 In 2nd para from bottom, "it's design" ==> 10/29/01 "its design". 10/11/01 gn 118 In first line of second bullet, "const iterator" 10/29/01 ==> "const_iterator". The latter should be in code font. ! 7/25/01 sb 119 One can't just replace "i-ci >= 3" with 10/30/01 "ci+3 <= i", because ci+3 might not be a valid iterator, e.g., it might be beyond the end of the container. I replaced the suggested workaround with a new one based on casting i to a ConstIter. ! 8/22/01 jep 121 I added a footnote telling readers that the 10/29/01 approach described in this Item may fail for reference-counted strings and pointing them to jep's comment on this matter below. 7/ 4/01 ajf 121 In second paragraph from the bottom, "then move 10/29/01 it forward it until" ==> "then move it forward until" 7/10/01 dm 126 Everywhere on page, "operator<<" ==> 10/29/01 "operator>>" 8/ 4/01 dg 136 In last para, "which reorders element" ==> 10/29/01 "which reorders elements". 8/23/01 sdm 144 In the lower diagram, non-code text in 10/29/01 "remove_if's return value" should be in text font. 10/29/01 sdm 144 In the upper diagram, the words "uncertified" 10/29/01 should be in text font. ! 8/22/01 jep 159 In the second call to accumulate on this page, 10/29/01 1.0 should be 1.0f. The comment should also be adjusted, as should the sentence after the example. 7/23/01 jeh 159 In 2nd prose para, "a floating pointer numbers" 10/29/01 ==> "a floating point number". 8/ 3/01 sdm 160 In the para following the code, there should be 10/29/01 no line break between "paragraph" and "2". ! 7/23/01 jeh 185 In last line of last code fragment, 10/29/01 "bind2nd(plus<int>" ==> "bind2nd(plus<double>". The next sentence needs to be correspondingly modified. 8/18/01 sp 187 Once in a code example on each page, 10/29/01 188 "vector<int> iterator" ==> 189 "vector<int>::iterator". 7/23/01 imt 199 At end of 2nd-to-last para, note that for set 10/29/01 and map, count must return 0 or 1, and that's why find has no speed advantage for those containers. 8/23/01 sdm 200 In the entry for equal_range in the next-to- 10/30/01 last row of the table, add "then distance". Make the same change to this table on the book's inside front cover. 7/ 8/01 ajf 209 In first line after the bulleted list, <set> 10/29/01 and <functional> should be in code font. 8/30/01 ab 211 At end of 2nd para, "Another STL platform I 10/29/01 uses..." ==> "Another STL platform I use..." 7/ 7/01 sdm 216 As noted below, it's becoming more common for 10/29/01 vector and string iterators not to be pointers. The first bullet on this page needs to be reworded. 8/ 4/01 dg 221 In 2nd para, "do fire up" ==> "do is fire up". 10/29/01 8/28/01 jtw 228 A more reliable URL for [27] is 10/29/01 http://www.research.att.com/~bs/stack_cat.pdf. 7/ 8/01 ajf 235 In first para under "Case-insensitive string 10/29/01 comparison," "The time, though" ==> "This time, though" 7/ 1/01 hs 239- Many of the apostrophes in this Appendix are 10/29/01 244 "straight" instead of "curly." 7/16/01 jf 251 Column 1, "NiftyEmail" entry. The page number 10/29/01 212 has been split into 21 and 2. 7/16/01 jf 253 Column 2, "types in containers" (sub-sub entry 10/29/01 for "iterators"). The spacing of the "see also iterator . . ." text is gappy. 7/16/01 jf 254 In several places, "Microsoft'" ==> 10/29/01 260 "Microsoft's". 7/16/01 jf 256 Column 2, "range" entry: The sub-sub entry "to 10/29/01 avoid . . ." is gappy. 10/28/01 sdm 256 Add entry "RB Tree, see red-black tree" 10/29/01 10/29/01 sdm Inside Diagram for Implementation D is missing the (By AW) Back shading that's present in the corresponding Cover diagram on page 71.
The following changes were made for the fourth printing of the book. These changes apply to your copy of Effective STL only if it's one of the first three printings.
DATE DATE REPORTED WHO PAGES WHAT FIXED -------- --- ----- ------------------------------------------------ -------- 7/19/01 sdm 17 The case for erase isn't quite as bad as the case 7/25/04 for insert, because you can safely erase the last element of a vector, deque, and list without invalidating iterators/pointers/references to elements preceding it in the container. ! 6/29/01 jk 20 The first para of Item 3 is incorrect: front 7/25/04 and back do NOT return copies of elements, they return references to elements. I removed all mention of front and back. 5/22/02 sxb 25 In para after the 1st code fragment, "more than 7/25/04 one function call" ==> "more than one statement" 2/ 4/03 shh 39 In second-to-last code comment, "create a SPW" 7/25/04 ==> "create an SPW". !11/29/02 gm 44 Regarding the paragraph after the first code 7/25/04 example, the call to erase can't take logarithmic time for multi containers, because such containers might consist entirely of elements with the value to be removed. I reworded things. 9/ 4/02 ga 46 In the for loop in the first code example, 7/25/04 "AssocContainer" should be entirely in italics. 8/ 1/03 lfr 51 In 2nd-to-last para, "unsigned integral value" 7/25/04 ==> "unsigned integral type" 11/ 6/02 wb 57 In the second code example, the 7/25/04 SpecificHeapAllocator template is missing the word "class" at the beginning of the template definition. !11/ 5/01 sdm 61 In 2nd-to-last para, the claim that C++ 7/25/04 guarantees that local objects are destroyed if an exception is thrown is not quite true. The guarantee holds only if the exception is caught. I added a footnote explaining this caveat. 7/ 3/02 kes 67 To third bullet, add a remark that calling 7/25/04 reserve never changes the number of objects in the container. (Unfortunately, when I did this, I wrote "resize" instead of "reserve," thus introducing an error not fixed until the 6th printing; see db's entry below for 2/3/05.) 9/27/01 lz 77 In the second section of example code, the call 7/25/04 to vd.resize(...) is missing the final closing parenthesis. 2/ 1/03 lfr 90 Missing colon at end of page. (The missing colon 7/25/04 was actually deliberate, but I reworded the end of the sentence to "try this:", which I think is clearer.) 7/13/02 ckl 91 In first code example, ssp's type should be 7/25/04 declared to be set<string*, stringPtrLess>. ! 2/ 4/02 sdm 106 In the lookup code using lower_bound (near the 7/25/04 middle of the page), the test should be this instead of what is in the book: if (i != vd.end() && !DataCompare()(s, *i)) ... The comment needs to be adjusted, too. The code in the book lets lower_bound use the default "<" as its comparison function, but the call to sort used a DataCompare object. In this particular example, the two tests do the same thing, but in general, it is critical to ensure that lookups in a sorted vector are done using the same comparison function as was used to sort the vector. 11/ 5/01 sdm 111 In 2nd-to-last line of Item 24, "map" should be 7/25/04 in code font. 7/22/01 dm 122- To create an iterator from a const_iterator, 7/25/04 8/22/01 jep 123 it's not actually necessary to have access to the container. Rather, you need to have access to some iterator i into the container that is no closer to end() than the const_iterator is. You can then use i as you would the container's begin iterator. I reworded to avoid the claim that access to the container is necessary. 3/16/02 lfr 124 The last word of the second sentence of the last 7/25/04 unbulleted paragraph has "i" in the wrong font. !11/ 5/01 ma 134 In last code example, "widgets.begin()+20" should 7/25/04 be "widgets.begin()+19". 9/ 4/02 ga 141 At end of second prose paragraph, "...you should 7/25/04 probably be calling partition..." ==> "...you should probably be calling partition or stable_partition..." 4/18/03 lz 157 In 1st line, "many elements" ==> "many elements 7/25/04 with a particular value" ! 8/16/01 kh 159 In the call to accumulate at the top of the page, 7/25/04 the literal 0 is incorrect. Because its type is int, accumulate will use int as its internal type for storing the partially accumulated sums. The correct type for this is string::size_type. It makes a difference, because int is signed and string::size_type is unsigned. 11/18/01 sk 160-1 PointAverage's constructor should list its member 7/25/04 initializers in the order in which the data members are defined in the class. (Shame on me for making this mistake, as it is the topic of Item 13 in my Effective C++.) 8/ 4/01 dg 162 The use of the term "components" in the 1st para 7/25/04 is confusing, because I never define that term. Reword. (In general, I use "component" in this book to mean "something in the STL.") 9/17/03 hs 163 In the middle of the page, 7/25/04 DoSomething::operator() should be declared public. 8/21/01 sdm 165 BPFCImpl should inherit from unary_function. 7/25/04 2/26/03 shh 166 In the third bullet point on the page, "returns 7/25/04 true or false" ==> "returns true or false (or something that can be implicitly converted to true or false)." 1/ 8/02 sdm 169 In code comment, "widget" should be capitalized 7/25/04 in "pointer-to-widget". Also, two comments on this page should be reworded. It's the Widgets that are or are not interesting, not the pointers to them. 9/25/02 pn 171-172 Some examples here fail to explicitly state that 7/25/04 inheritance from e.g., std::binary_function is public. For consistency with what I do everywhere else in the book, they should. 1/29/02 lfr 176 Last sentence of second-to-last para is missing 7/25/04 the word "to". 7/28/03 jp 206 Reword problem statement to: "get rid of all the 7/25/04 207 elements in the vector whose value is less than x and that occur after the last value at least as big as y". !10/ 4/01 rd 207 The comment above the initialization of 7/25/04 rangeBegin is incorrect. It should read as follows: Initialize rangeBegin to point to the element following the last occurrence of a value greater than or equal to y. If there is no such value, initialize rangeBegin to v.begin(). If the last occurrence of the value is the last element in v, initialize rangeBegin to v.end(). 2/26/03 shh 211 In line 5 of 4th prose para, "do this is with" 7/25/04 ==> "do this with" 7/20/04 gc 228 Regarding reference [24], the article appeared in 7/25/04 December 2000 (not November). 11/ 2/02 cb 253 In column 1, the entry for istream_iterators 7/25/04 mentioning operator<< should mention operator>>. 11/ 2/02 cb 255 In column 2, the entry for operator<< should 7/25/04 mention operator>>.
The following changes were made for the sixth printing of the book. These changes apply to your copy of Effective STL only if it's one of the first five printings.
DATE DATE REPORTED WHO PAGES WHAT FIXED -------- --- ----- ------------------------------------------------ -------- 2/ 3/05 db 67 In final sentence of third bullet (added per 2/ 3/05 kes's 7/3/02 bug report above), "resize" ==> "reserve".
The following changes were made for the seventh printing of the book. These changes apply to your copy of Effective STL only if it's one of the first six printings.
DATE DATE REPORTED WHO PAGES WHAT FIXED -------- --- ----- ------------------------------------------------ -------- 5/24/02 en 12-14 Add a bullet with the question, "Do you care if 10/ 5/05 using swap on containers invalidates iterators, pointers, or references?" If so, string is out, as noted in the bug report by ja and en for page 79 above. 2/ 5/02 sdm 18-19 The text suggests that the WCIterator typedef 10/ 4/05 (near the bottom of the page) adds abstraction, but it doesn't. WidgetContainer::iterator is just as abstract, because iterator is itself an abstraction. typedefs for iterator types are still attractive, however, because they can save a lot of typing (e.g., WCIterator instead of WidgetContainer::iterator). 7/28/01 jep 29 The statement near the end of para 2 that input 10/ 4/05 iterators require that elements be moved into their final positions one place at a time is incorrect. Implementations are permitted to do that, but they are not required to, and more efficient approaches are possible. 11/04/03 sdm 29-30 In contrast to when I wrote the book, current 10/ 4/05 7/28/04 sk 66 vector implementations often use a growth 67 factor other than 2. I revised the book to eliminate comments suggesting that 2 is the most common growth factor. 9/18/04 dxm 44 The comment next to the call to remove_copy_if 10/ 4/05 near the bottom of the page could suggest that values are removed from c before copying them to goodValues. In fact, c is not modified at all; undesired values are simply skipped during the copy. I reworded the comment to say that the "desired" values are copied. 10/11/01 gn 67 In second bullet, it is worth noting that there 10/ 4/05 is also a two-argument version of resize, the second argument specifying the value to copy into new elements if the container needs to be increased in size. 12/21/04 nds 67 In the description for resize, it's not true 10/ 4/05 that if n is greater than the current size, new default-constructed elements will be added. Rather copies of a single default-constructed element will be added. 8/22/01 jep 68 At end of 2nd-to-last para of Item 14, note that 10/ 4/05 any use of push_back would invalidate an end iterator, e.g., one initialized from s.end(). ! 8/23/01 ja 78 When string implementations use reference 10/ 4/05 counting, the swap trick using the copy constructor doesn't decrease the capacity, because the copy constructor isn't allocating any memory; it's just adjusting a reference count. A more reliable way to perform shrink-to-fit is to create the temporary string via the range constructor, e.g., like this for the last line of code on page 78: string(s.begin(), s.end()).swap(s); This version of the swap trick is safer for vectors, too, because it eliminates any chance that the copy constructor will copy the other vector's excess capacity (which implementations are permitted to do). I changed both swap trick examples on this page to use the range constructor instead of the copy constructor. 1/31/03 lfr 91 Include an xref to Item 7 near the definition 10/ 4/05 for DereferenceLess for readers who are confused about why DereferenceLess is a non-template struct containing a templatized operator(). 10/ 4/05 sdm 96 Added comment to the last code example to 10/ 4/05 indicate that it should not compile per the changes to pg. 97 below. I also reworded some surrounding text to avoid claiming that the code is legal. ! 8/22/01 jep 97 The standardization committee has clarified 10/ 4/05 that modifying set or map keys without a cast should not compile. I added a footnote to this effect, also noting that nonconformant STL implementations continue to be used. 9/17/03 hs 99 The claim in the 3rd prose para that map nodes 10/ 4/05 could be put in write-protected memory is dubious. Among other things, the value part of the pair is generally modifiable, and the node almost certainly has pointers to its children, which may change over time. I removed the statement. 9/ 8/01 dxc 101 The approach described in this Item makes sense 10/ 4/05 only if the performance of Phase 2 (Lookup) is vastly more important than the performance of the other phases. 9/18/05 fxs 103 Need to mention that emulating a set or map 10/ 5/05 106 using a vector requires making sure there are no duplicates in the data by the end of Phase I. I added comments to the code, as there was no space to add a proper discussion of this matter. (See also the comments below on this topic.) ! 8/20/01 ag 108 The 2nd-to-last para is incorrect. Both the 10/ 5/05 call to operator[] and to insert generate a temporary pair that must be constructed and destructed. The only real difference is that calling insert saves a call to the assignment operator. 5/ 1/05 af 134 In the first code example, the 2nd parameter to 10/ 5/05 partial_sort should be widgets.begin()+20. In the second code example, the 2nd parameter to nth_element should be widgets.begin()+19. (The comments for both code fragments are correct.) 6/28/04 he 197 The statement in the 2nd prose paragraph that 10/ 4/05 "equal_range not only does the job of find for sorted ranges, it also replaces count" is incorrect, because this part of the Item is discussing STL algorithms, and the equal_range algorithm is based on equivalence, while the find and count algorithms are based on equality. I reworded to clarify that the statement is true only for types where equality and equivalence yield the same results. 6/20/00 das 201 The text is not clear enough that find on a 10/ 5/05 multi container need not find the first occurrence of a value. I reworded the paragraph very slightly, but this is just the tip of a bigger iceberg. For details, see my comment on the table in Item 45 below. 10/ 4/05 sdm 225 Added an unnumbered citation to the third 10/ 4/05 edition of Effective C++, and clarified that the Effective C++ CD has a copy of the second edition of that book. 8/31/05 lfr 234 In the 3rd paragraph, "c" and "char" should be 10/ 4/05 in code font. 2/28/04 mp 257 Add an index entry under "set" pointing to page 10/ 4/05 199 for "idiomatic test for membership."
The following changes were made for the eighth printing of the book. These changes apply to your copy of Effective STL only if it's one of the first seven printings.
DATE DATE REPORTED WHO PAGES WHAT FIXED -------- --- ----- ------------------------------------------------ -------- 6/ 7/06 sdm 47 Footnote symbol should immediately follow 6/ 7/06 121 punctuation, not precede it. 12/28/05 vxs 61 In footnote, "ma y" ==> "may". (I have no 6/ 7/06 idea why the FrameMaker spell checker does not catch this. I ran it, trust me.) 5/ 2/06 rxp 72-73 The bottom part of pg. 72 says that 6/ 7/06 Implementation C reserves no space for a trailing null, but the bottom part of pg. 75 implies that I know of no contemporary library implementation where a trailing null is not stored (which is true). Unfortunately, I am unable to reproduce the results for Implementation C described on pg. 72, so I removed mention of Implementation C from the bottom of page 72 (which caused a change in the break between pages 72 and 73). 4/17/06 txs 131 Unlike front_inserter and back_inserter (which 6/ 7/06 always call push_front and push_back, respectively), inserter returns an iterator that keeps track of where to perform its next insertion. I added a footnote to this effect. 1/ 2/06 vxs 152 In line 7 of final para, "return false" ==> 6/ 7/06 "returns false". 3/28/06 cmm 190 Last word on page: "is" ==> "are". 6/ 7/06 1/ 7/06 mxd 205 Per the resolution of core language issue 115, 6/ 7/06 the line of code at the top of this page is now valid. I added a footnote to this effect.
The following changes were made for the tenth printing of the book. These changes apply to your copy of Effective STL only if it's printing 7, 8, or 9.
DATE DATE
REPORTED WHO PAGES WHAT FIXED
-------- --- ----- ------------------------------------------------ --------
3/14/07 cxb 68 In the 9th printing only, in code at top of page, NA
the following line of red code is missing between
the two black lines:
v.reserve(1000);
(This was an error introduced during printing.
The book source itself is correct, hence the lack
of a fix date.)
9/27/06 gxu 100 Point 3 from the bottom of page 99 is repeated 10/ 4/05
at the top of page 100. (This error was
introduced in the 7th printing, when I modified
pages 99 and 100 but sent the printer only the
new page 99, sigh.)
The following changes were made for the 12th printing of the book. These changes apply to your copy of Effective STL only if it's one of the first 11 printings.
DATE DATE REPORTED WHO PAGES WHAT FIXED -------- --- ----- ------------------------------------------------ -------- 5/21/08 jxn 77 In code comment near top of page, remove space between "(" and "see". 5/??/08 9/15/07 dmr 145 In 3rd para, "containers of dynamically allocated 8/12/09 pointers" ==> "containers of pointers to dynamically allocated objects". 4/15/08 nxh 152 In first line, "rect" ==> "correct". 8/12/09 4/22/08 ajs 205 In penultimate line, "programing" ==> 8/12/09 "programming". 8/12/09 sdm 205 In footnote, "anticipated to be in 2009" ==> 8/12/09 "anticipated to be around 2011". 1/24/08 sdm 225 In the second bullet entry, reformat "Second 1/25/08 Edition" to match how all other edition references are formatted. 2/ 4/08 sdm 226 Revise [4] to refer to [21] instead of 8/12/09 giving URL. 1/24/08 sdm 226 Revise [5] to refer to the 2003 edition and 1/25/08 avoid mentioning the price. (It's now $30). 8/18/08 sdm 226 Revise [9] to reflect that the book has 8/12/09 now been published. 1/15/08 mxs 227-228 For [19], replace the URL with 1/25/08 http://erdani.org/publications/traits.html. For the second bullet entry after [27], replace the URL with http://www.ddj.com/cpp/184401382. For [29], replace the URL with http://www.aristeia.com/BookErrata/ auto_ptr-update.html. 3/11/08 sdm 228 Remove question mark from end of article title ??/??/08 in second bullet entry after [27]. 3/11/08 sdm 228 URL for bullet entry above [28] should be ??/??/08 http://www.aristeia.com/BookErrata/ ec++3e-errata.html. 7/2/08 sdm 259 Remove index entry for "URLs, for Effective 8/12/09 C++ CD demo".
The following changes were made for the 14th printing of the book. These changes apply to your copy of Effective STL only if it's one of the first 13 printings.
DATE DATE
REPORTED WHO PAGES WHAT FIXED
-------- --- ----- ------------------------------------------------ --------
8/31/11 sdm xii Replaced estl@aristeia.com with 2/13/12
smeyers@aristeia.com for comments on book content.
8/24/09 mam 5 Italicize "complexity guarantees" in first 2/13/12
sentence of last paragraph.
! 5/23/11 axw 52 In declarations of set objects on these pages, 2/13/12
57 the allocator type is specified as the second
template argument, but it should be the third;
the examples are missing the type of the
comparison function.
6/ 9/10 rsb 154 Clarify that the version of ciStringCompare 2/13/12
shown on this page is the one with a strcmp-like
tri-value interface, not the one suitable for
use as an STL comparison function.
The following changes were made for the 15th printing of the book. These changes apply to your copy of Effective STL only if it's one of the first 14 printings.
DATE DATE REPORTED WHO PAGES WHAT FIXED -------- --- ----- ------------------------------------------------ -------- 2/23/13 bvw 19 In highlighted declaration for SpecialAllocator, 4/29/13 "class" should precede "SpecialAllocator".
The following changes have been proposed but have not yet been published:
DATE DATE REPORTED WHO PAGES WHAT FIXED -------- --- ----- ------------------------------------------------ -------- 9/20/18 lfr Inside The table on the inside front cover is missing Front the "(see below)" remark in the last cell of Cover, row 2 that's present in the table on page 200. 200 That remark could be more clearly worded, e.g., "(see discussion)".
What follows are interesting comments about the material in Effective STL, 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 -------- --- ----- ----------------------------------------------------------- 6/22/01 lz Many Thanks to Leor Zolman, all the code fragments in the book are available in compilable form at http://www.bdsoft.com/resources/estlcode.html. 5/ 8/01 sdm Many STLport debug mode is no longer the only STL 6/27/01 pe implementation where vector's and string's iterators aren't real pointers. The latest Dinkumware library (including the one shipped with VC .NET) also uses classes for these iterator types, and I'm told that the same is true of the library that ships with GCC 3.0. 5/ 9/01 sdm Many In most places where I mention arrays, I should mention valarrays, too. Like vectors, valarrays are constrained to have contiguous storage, and this means that pointers can be used as iterators into valarrays. 8/31/08 lfr Many The C++ Standard offers no guarantees about the order in which the elements of a range are visited within an algorithm, but the book routinely assumes that elements are visited in order from beginning to end. In practice, this is probably a safe assumption, but it is an assumption for which there is no backing in the Standard. 11/11/10 jxb Many The book fails to discuss the interaction of NaNs and the STL. All comparisons against NaNs fail, which affects functions that depend on equality (e.g., std::find, which will never find a NaN), functions that depend on equivalence (e.g., std::sort, which will view NaNs as equivalent to every value), and functions that depend on any other comparisons (e.g., "<"). Fundamentally, the STL is designed to work with "normal" values, and NaNs, being distinctly abnormal values, virtually always lead to undefined behavior in the STL. (This could be an Item in its own right: "Avoid using NaNs" or maybe "Be wary of NaNs," with the understanding that the advice applies only to mixing NaNs and the STL, not to the use of NaNs in general.) 7/28/01 jep 5 In second bullet, the summary of input iterators is subtly incorrect. Input iterators may be read more than once, but they support only single-pass algorithms. Once you've incremented past an element, you can't get back to that element. 9/24/01 mm Item 1 Sometimes, the best data structure for a problem is not in the STL at all. mm writes that "One of the biggest misuses that I've seen of the STL is when maps are used instead of sparse matrix data structures. ... In many applications, a matrix is very sparse. It is often the case that there is just 2 to 5 entries per column, even in matrices with tens of thousands of rows. ... There are highly efficient data structures for doing this, and they're not very complicated. ... There are lots of efficient algorithms available for doing all sorts of operations on a matrix, and there are various places on the internet (especially www.netlib.org) that have classes that encapsulate this." 7/15/01 sdm Item 1 For another discussion of the pros and cons of different containers, check out Andrew Koenig's and Barbara Moo's column, "Which Container Should I Use?," appearing in the August 2001 C/C++ Users Journal. 4/28/02 sdm Item 1 In his May 2002 Dr. Dobb's Journal article, "Disk Thrashing & the Pitfalls of Virtual Memory," Bartosz Milewski describes another consideration to take into account when choosing between vector and deque: the impact of repeatedly copying objects in order to keep vector's memory contiguous. 3/21/02 ss Items The rules governing the conditions under which iterators 1,26,28 are or are not invalidated fail to apply to reverse_iterators. Some operations on node-based containers (e.g., insertion) that invalide no iterators MAY invalidate reverse_iterators. ss sent this example: std::list<int> int_list; int_list.push_back(1); std::list<int>::reverse_iterator iter = int_list.rbegin(); std::cout << *iter; // prints "1" int_list.push_back(2); std::cout << *iter; // prints "2" (doh!) If you're interested in more information on this, take a look at a comp.std.c++ thread on this issue. 12/ 5/07 dd Item 1 Another consideration is container iteration speed, which generally decreases in this order: vector/string (fastest iteration), deque, list, set/multiset/map/multimap (slowest iteration). 9/26/01 kh 13 Technically, it would be more accurate to define contiguous-memory containers as those that are assumed to store more than one element per dynamically allocated chunk of memory; they are not required to do so. In theory, both deque and string could be implemented as arrays of pointers to objects, for example, though no sane implementation would do things that way. (Very large objects may be stored only one element per chunk of memory in a deque, though one would have to wonder why such large objects were being stored in an STL container in the first place.) 7/16/01 sdm Item 4 If you're interested in the technical and standardization issues surrounding list::size, check out the July 2001 comp.std.c++ thread discussing the matter. 10/11/01 gn 33 gn writes: Regarding the declaration of the function int f(double(d)) at the bottom of the page, the text suggest that the parentheses are ignored. Well, it depends on what d is. If it is a type-name then the function is int f(double (*)(d)), and that is not the same as int f(double d). The d must be looked up in this case to determine if it is a type-name or not. See 8.2/7. typedef int d; int f(double(d)); // d is a type-name => // int f(double (*)(int)); int d; int f(double(d)); // d isn't a type-name => // int f(double); 6/ 4/04 tb Item 7 tb argues that the Item title should make clear that this Item applies only when the container owns the pointers, i.e., is responsible for deleting them. That's true, of course, but I hope the discussion in the Item makes that clear. In a future edition, I may reword the Item title. 8/26/02 sdm Item 7 Several people have written to ask about why DeleteObject::operator() takes a pointer to const, even thought it's going to delete the pointer. The answer is that if it did not, it wouldn't be possible to use DeleteObject on containers such as vector<const char*>. There has been much debate in the C++ community over whether deleting pointers-to-const should be legal, but it is and it can be useful, so it's important to me that DeleteObject support it. 12/22/01 sdm Item 7 Windows programmers experimenting with my DeleteObject class should beware that there is a Windows function with the same name. (I didn't know that when I wrote the book.) 7/11/07 axm Items Item 9 discusses how to erase while iterating, and Item 28 9, 28 discusses how to erase using reverse_iterators, but neither Item discusses how to erase while iterating with reverse_iterators. For information on this issue, see the newsgroup discussion of the issue that axm initiated. 6/29/01 kl 44-46 "AssocContainer<int>" isn't really appropriate for map and multimap. This is true, but I can't think of a better term, and I don't think the current term is too misleading. 7/28/01 jep 46 The approach I show for erasing elements in a contiguous- memory container while iterating through it does a good job of maintaining iterator validity, but the time complexity of the approach is quadratic. This can typically be improved to linear by using a two pass strategy: 1. Walk the container, writing the log for each element you plan to erase (but don't erase anything yet). 2. Perform a range erase, e.g., by using the erase- remove idiom or by using partition (or stable_partition) and then erasing. 12/ 2/02 jr 46 The code at the bottom of this page has two shortcomings: (1) though it works when iterating over an entire container, it's incorrect if given an arbitrary end iterator, because the call to erase will invalidate the end iterator; and (2) because each call to erase shifts all succeeding elements down by one, the linear-looking loop really runs in quadratic time. Here's code that addresses both problems, where endIt is the arbitrary end iterator to be used and, for consistency, beginIt is an arbitrary begin iterator to be used: vector<int>::iterator i = beginIt; while (i!=endIt && !badValue(*i)) ++i; vector<int>::iterator j = i; while (i!=endIt){ if (badValue(*i)) { logFile << "Erasing " << *i << '\n'; } else { *j=*i; ++j; } ++i; } c.erase(j, endIt); Note that the second while loop is essentially a variant of remove_if (see Item 32). jr reports that in simple tests he performed comparing the performance of this code with that on the bottom of page 46, he saw speed improvements of 2-3 orders of magnitude. 11/26/16 sxl 46 If it's acceptable to erase the "bad" elements in reverse order, the following code can be used in place of what's shown on the bottom of the page: for (SeqContainer<int>::reverse_iterator i = c.rbegin(); i != c.rend(); ) { if (badValue(*i)) { logFile << "Erasing " << *i << '\n'; c.erase( std::next(i++).base() ); } else ++i; } This should run as fast as the code in jr's comment of 12/2/02 (above), but, unlike jr's code, it calls the destructor of each erased element at the time it's erased. 11/14/01 axg Item 10 One way to avoid creating allocators with per-object state is to declare all member functions static. 10/11/01 gn 53 Though the book is correct that the type of the allocator for ListNodes is Allocator::rebind<ListNode>::other you'd have to express that type like this in a program: typename Allocator::template rebind<ListNode>::other Pages 7-8 explain why the "typename" is necessary, and the use of "template" here is similarly required to help the parser process things correctly. 11/28/01 sdm Items Matt Austern has a nice article on implementing a 10-11 debugging allocator and allocator adapters in his December 2001 column, "A Debugging Allocator." ! 8/16/01 kh 55-56 My discussion of putting containers in shared memory is incomplete and, to some degree, misleading. As Item 15 demonstrates, some string implementations use the small string optimization, so elements of such strings won't be in shared memory unless the string objects themselves are. Furthermore, even use of placement new to put containers in shared memory won't put static components of those containers in shared memory, and the Standard allows containers to have such components (e.g., a shared empty string representation); some implementations take advantage of this allowance. kh summarizes things this way: "No matter how well-written your allocator implementation [for shared memory], if it works, it is either a matter of luck or hardwiring to a specific container implementation." 11/ 5/01 sdm 60-61 An alternative to creating and using the Lock template is to use Alexandrescu's and Marginean's ScopeGuard technique. 11/13/01 ib 60-62 Given that manual concurrency control is a necessity, you might consider using the cross-platform threading library available at Boost. 8/22/01 jep 66 jep notes that "The 'aptly named max_size member function' does nothing more than return a number based on the number of bits in size_type. It has nothing to do with how many items may really be placed in any of the containers without exceeding memory." 8/18/02 apl 69 apl argues that credit for notion that "God is in the details" should go to Mies van der Rohe, not Einstein. He points to a column in The Atlantic online to bolster his argument. 8/19/01 hxh 72-73 Regarding Implementation B's capacity being 7 when the size of the string is 5, hxh (the author of Implementation B) writes: At the time I wrote <string>, I could not imagine an allocator that could deliver a non multiple of sizeof(void*) bytes on the platforms I was targeting. I could imagine specialty allocators that could very efficiently deliver 4 bytes, but not 1, 2 or 3 bytes. Or 8 bytes, but probably not 5, 6 or 7. So string takes advantage of this. If the client asks for 5 bytes, he gets 7 (8 minus 1 for the terminating null). So this string really does have a minimum capacity. It's 3. I tend to go for very small minimum capacities in order to make containers of containers more efficient. 9/12/01 sdm 74 A number of people have expressed interest in the source for my claim that the elements of a vector must be stored in contiguous memory. This guarantee is not in the Standard itself. Rather, it will be part of a forthcoming Technical Corregendum to the Standard, something of which all library implementers are certainly aware. For more information on this matter, consult the official defect report (Library Working Group Issue #69). 3/29/04 df 74 An alternative to "&v[0]" is "&v.front()". df argues that this is "the most explict way to do it." To me, "&v[0]" is equally explicit, but both work. 8/17/07 abt 74 abt remarks: I don't think you should avoid calling doSomething altogether just because the vector is empty. Perhaps doSomething has Something useful to do, even if you give it zero elements. So I think the example should be changed to doSomething(v.empty() ? 0 : &v[0], v.size()); or, perhaps even better (as Daniel Filip had suggested on the errata site), doSomething(v.empty() ? 0 : &v.front(), v.size()); 3/10/09 axa 75 This blog entry at Van's House makes clear that the current C++ standard is ambiguous about the statement that strings need not be stored in contiguous memory, and it makes even clearer that any ambiguity about the situation is eliminated in C++0x. 7/ 8/01 dm 80 Technically, the statement at the bottom of page 79 may compile. The real problem is that even if it does, the statement *pb = true; can't affect the value of v[0], because it's not possible to have a pointer to a bit. 11/27/07 cpj 81 Another alternative to vector<bool> is basic_string<bool>. 12/22/07 nxd 81 Other alternatives to vector<bool> include vector<unsigned char> and Boost's dynamic_bitset. 7/31/01 gl Item 20 When your comparison function for an associative container isn't less<T>, it's important to specify the comparison function for all algorithms that will perform comparisons. An example of this issue is discussed on page 149 in Item 34. Note that following the advice of Item 44 minimizes the chances of running into this kind of problem. 8/22/01 jep 90-91 You don't have to create a functor class, because you could use stringPtrLess's type, then pass stringPtrLess as a constructor argument: bool stringPtrLess (string const*, string const*); typedef bool (*StringPtrLess) (string const*, string const*); set<string*, StringPtrLess> ssp(stringPtrLess); This is legal code, but I consider it highly ill-advised, because it allows for the possibility that you have multiple containers of the same type but with different sort orders. To me, that's a recipe for disaster, and that's why I went out of my way to avoid mentioning it in the book. 6/16/13 cxp 91 Regarding my DereferenceLess struct, cxp writes: The drawback with your method is that you have to redefine all of the STL functors. That is a lot of work, if instead you make a wrapper you can have it wrap all binary_functions(for instance). Here is what I would suggest for that item: template <typename T> struct Dereference { typename T::result_type operator()(const typename T::first_argument_type* arg1, const typename T::second_argument_type* arg2) const { return T()(*arg1, *arg2); } }; std::set<string*, Dereference<std::less<string> > > myset; 8/22/01 jep Item 21 jep writes: Using less_equal is even worse than you say. The average quicksort used in sort will crash with some data sets. Neither 10A nor 10B will be in the range of equal_range. For { 9 10B 10A 11 } I got find(10) is end, lower_bound(10) is 11, upper_bound(10) is 10B, and equal_range(10) is [11, 10B), an invalid range. 6/20/01 cc 93 Writes cc: The comparison type StringPtrGreater can be implemented in terms of comparison type StringPtrLess: struct StringPtrLess: binary_function<const string*, const string*, bool> { bool operator()(const string* ps1, const string* ps2) const { return *ps1 < *ps2; } }; struct StringPtrGreater: binary_function<const string*, const string*, bool> { bool operator()(const string* ps1, const string* ps2) const { return StringPtrLess()(ps2, ps1); } }; Not only does this ease the maintenance, but also, more importantly, expresses the logic: To determine if x > y, we just need to test if y < x. That is because a < b and b > a are necessary and sufficient conditions for each other. 3/29/17 rxh Item 22 If you want to portably change non-key fields in an object stored in a map or multimap, but you don't want to follow the five-step approach described on pages 99-100, you can declare the fields you want to modify mutable. Such fields can be portably changed even in const objects. This approach can also be used with sets and multisets, in which case there is no need to cast away an object's constness prior to modifying its mutable non-key fields. 10/ 5/05 sdm Item 23 As noted above, vectors emulating sets and maps must manually ensure that the data contain no duplicates. Three ways to ensure this are (1) to know a priori that the input contains no duplicates, (2) to invoke the "unique" algorithm on the vector after sorting it, and (3) to put the data into a normal set or map during Phase 1, then copy it into a vector at the end of Phase 1; use of the set or map will automatically sort the data and eliminate duplicates. 12/ 5/07 dd Item 23 Sorted vectors can also outperform associative containers when container iteration is an important operation. dd reported that in one system he examined, iteration over a vector was 35% faster than over a set. 8/ 4/01 sdm Item 23 As part of the Loki library described in his book, Modern C++ Design (Addison-Wesley, 2001), and downloadable from the Loki web site, Andrei Alexandrescu developed the AssocVector template, a map-like container built on top of sorted vectors. If you're interested in the performance improvements you might get from using a sorted vector instead of a map, consider downloading AssocVector and giving it a try. 9/15/15 sdm Item 23 In view of the addition of the unordered (hash table-based) containers to the Standard Library as of C++11, it may be that situations where a sorted std::vector made sense in C++98 are now better served by an unordered container. For an overview of this idea, check out my blog post on the topic. 1/ 4/04 or Item 24 Another advantage to a function like efficientAddOrUpdate vis-a-vis operator[] is that use of operator[] requires that the value type of the pair (i.e., the mapped_type) support default construction for insertion, but efficientAddOrUpdate does not. 8/20/01 ag 110-111 Writes ag: The discussion about using a generic ValueArgType to use the specialized assign if present is interesting, but using KeyArgType instead of key_type may trigger multiple conversions for the key. Imagine having a map indexed by strings and calling efficientAddOrUpdate(m,"Andrea",10.5); With the version in the book there are three conversions from KeyArgType to key_type: one in lower_bound, one in key_comp and another one in insert. 11/12/01 sdm Item 25 Regarding the choice of basing hashed containers on equality or equivalence, P. J. Plauger, founder of Dinkumware, posted this to comp.lang.c++.moderated on 8/27/01: Our latest version of the hash template classes aims for the best of both worlds. Turns out it can hash properly given either a strict weak ordering, as in operator less<T>, or an inequality comparison, as in operator not_equal<T>. So we add a partial specialization that looks for SGI-style template parameters and invert the sense of the supplied predicate. The upshot is that you can use our hash tables as a drop-in replacement for map/set, using a strict weak ordering, or as a drop-in replacement for SGI-style hash_map/set, using an (in)equality comparison. If you're interested in the choice between equality and equivalence for hashed containers, you might want to view the thread from which this posting is taken. 2/20/02 sdm Item 25 For information on how hash-based containers may be added to the next version of the Standard Library, consult Matt Austern's April 2002 column, "Hash Tables for the Standard Library." 3/26/06 txs 113 Traits are also explained in the third edition of Effective C++ :-) 5/16/03 drm Item 26 "The advice of this Item seems kind of strong. Counting in my last bit of code: 49 const_iterators, 3 iterators, 0 problems (so far). I think a better slant to the Item might be: be careful, const_iterators have certain restrictions. I don't see that those restrictions necessarily lead to the recommendation to prefer iterator." 9/ 4/02 ga 117 Five lines from the bottom, "const" should be capitalized, because it is the first word in a sentence. ! 8/16/09 sxv 117 It is possible to convert an iterator to a reverse_iterator, but the conversion is not implicit. 8/22/01 jep 118-119 The Standard doesn't actually state that comparisons between iterators and const_iterators must be supported. Now, however, the Standardization Committee appears to be on the verge of officially deciding that such comparisons must be allowed. For details, consult Library Working Group Issue #179. While you're there, note the link to Issue #280, where you'll see that whether to require comparisons of reverse_iterators and const_reverse_iterators is not yet resolved. ! 8/22/01 jep 121 The advance/distance idiom shown here is sanctioned by the Standard for every standard container except string, and it should also work for any string implementation that avoids reference counting. For strings using reference counting, calling begin() may invalidate existing iterators, and that leads to this problem: typedef string::iterator Iter; typedef string::const_iterator ConstIter; string s; ConstIter ci; ... // make ci point into s Iter i(s.begin()); // calling begin // invalidates ci! advance(i, distance<ConstIter>(i, ci)); // pass invalidated ci // to distance! A use of advance and distance that should work with any standard container c (including strings employing reference counting) is this: Container::difference_type d = distance(static_cast<const Container&>(c).begin(), ci); Iter i(c.begin()); // invalidates ci, but we // don't need it any more advance(i, d); 7/22/01 dm Item 27 dm notes that both advance and distance are linear-time operations on some containers. The time to accomplish what the advance(distance(...),...) idiom does can be cut in half for containers that lack random access as follows: C::iterator i(c.begin()); if (ci == c.end()) i = c(end(); else while (&*i != &*ci) ++i; Writes dm: This is twice as fast on average, because the while loop shown above only traverses the elements once. (I timed it using two different compilers. Sure enough -- about twice as fast.) Neither solution is optimum for all iterator categories. The best solution is one that is parameterized by the category tag to invoke the advance(distance()) idiom only on random access iterators, and the while loop on all others. Perhaps this Item should be renamed to "Use distance and advance to convert a *random access* container's const_iterators to iterators." 8/27/02 jcj Item 28 When using the range form of erase, there is no need to adjust a reverse_iterator's base if it marks the end of the erase range. Consider: vector<int> v; ... // Put 1-5 in v // Remove 2-4 from vector in example [1, 2, 3, 4, 5] vector<int>::iterator ifirst = // ifirst points find(v.begin(), v.end(), 2); // to the 2 vector<int>::reverse_iterator rilast = // rilast points find(v.rbegin(), v.rend(), 4); // to the 4 v.erase(ifirst, rilast.base()); // erase 2-4, // inclusive 9/ 4/02 ga 133 Writes ga, "Another variation: reserve, move away/copy the elements that would be moved one by one in one chunk and then transform on the gap that we are left with." I believe that in some cases, this will be more efficient than resize/copy. 6/18/01 sdm Item 31 Additional useful information on the STL's various sorting options can be found in Matt Austern's column in the August 2001 "Sorting in the Standard Library." 9/21/01 fk 136 At the top of the page, begin and end should probably be declared const. (There are other places where variables could be declared const, but a quick glance showed that methodically adding "const" would cause some formatting problems (new line breaks) and would, in some cases, probably call for additional explanatory text. Lest the cure be worse than the disease, I decided to leave things as they are. If there is a second edition of this book, I'll address the matter then.) 4/ 4/06 txs 136 There's more than one way to define the median and the 75th percentile. The way I show in the book limits values to those possessed by Widgets in the container, but other approaches are valid. For more information, see the Wikipedia entries for median and percentile. 9/13/07 abt 136 The initialization of goalOffset uses a floating point value, but goalOffset is integral. This elicits a warning with some compilers. In this case, we could initialize with widgets.size()/4, but in the general case, we could make the deliberate nature of the conversion clear by using a static_cast. 2/22/03 lfr Item 34 When using an algorithm expecting a sorted range (e.g., includes, set_union, etc.) on a standard associative container (especially a map or multimap), it's important to pass the correct comparison function. The easiest way to do this is to pass the result of the value_comp member function: typedef multimap<int, string> map1, map2; ... bool subMultiset = includes(map1.begin(), map1.end(), map2.begin(), map2.end(), map1.value_comp()); This works for sets and multisets, too, because for those types, value_comp returns the same thing as key_comp. However, as noted in Item 44, for operations like lower_bound, etc., it's generally better to use member functions instead of algorithms when both are applicable. 6/ 3/02 mkk Item 35 This Item proposes two versions of ciStringCompare, one with a strcmp interface and one with an operator< interface. They have the same signature and cannot coexist. This is frustrating because one may well need both, and it also makes the example in Item 19 ambiguous (which one was meant?) The example code would be more useful if the second function was called ciStringLess or some other distinct name. 6/ 9/10 rsb 154 Under POSIX, the strcasecmp function offers functionality akin to stricmp and strcmpi. (None of the three is standard in C or C++.) 2/20/03 lfr 156 Because postincrement is less efficient than preincrement, the if statement may be better implemented as follows: if (p(*begin)) { *destBegin = *begin; ++destBegin; } 8/ 3/01 yjz Item 37 Writes yjz: I agree that accumulate most clearly expresses what's going on. Personally, that's more intuitive to me. I would definitely choose accumulate when I do simple value accumulations. But for the final example in this item, I would definitely use for_each because the solution using accumulate provided by this item introduces a lot of overhead by calculating the average point every time the operator() is called. So, supposedly, we have n elements in the container, for the example using accumulate, you will calculate the average of points n times. But in for_each example, you only do that calculation once. For this specific example, there are 2*(n-1) times of division and (n-1) times of construction of temporary Point objects which are not necessary. 9/21/01 fk Item 37 fk remarks that the accumulate approach to computing 11/29/02 gm the average of a set of points involves multiple divisions, while the for_each approach does only a single division at the end. As a result, he suggests that the for_each approach may be more accurate. gm disagrees. He writes: "the results of all but the last of those divisions get thrown away. The actual calculations that contribute to the final answer are exactly the same for both versions; the only difference is that the version with accumulate (1) does far more divisions, (2) does a whole lot of unnecessary contructions and destructions of Point objects, and (3) isn't legal. It's possible that a sufficiently smart compiler might be able to eliminate all that wasted effort, I suppose." I responded that floating point makes my head hurt, and gm replied that "the point I'm making doesn't really have anything to do with floating point. The results of all those extra divisions you're worried about get thrown away immediately, that's all. They're used to make return values from PointAverage::operator(), which get passed to the next invocation of PointAverage::operator() and ignored there." 10/14/01 kg Item 37 There is a notable difference between the accumulate and the for_each approaches to this problem. When the range is empty, accumulate returns Point(0,0), but calling result on the functor returned from for_each yields undefined behavior due to division by zero. 2/26/03 shh 159 In order to make sure that the initial summary value passed to accumulate is of the appropriate type, shh suggests using this form: Y sum = accumulate ( begin, // acts like a T* end, // acts like a T* static_cast<Y>(initValue) // initValue need not be of type Y ); 8/30/08 lfr 160 Functors to be used with the standard adapters (not1, 161 not2, bind1st, bind2nd) must declare their operator() 163 functions const, so the standard adapters would not be 167 usable with the functors on these pages that have non-const operator()s, even though they inherit from unary- or binary_function. Their adaptability could be useful to non-standard adapters, however, if those adapters didn't require const operator() functions. 1/13/05 bxr 160 The following approach allows the average of a set of points to be computed by accumulate without its functor using any side effects: class AveragePoint { public: AveragePoint() : SumX(0), SumY(0), mv_NbrOfPoints(0) {} AveragePoint(const AveragePoint& av_AveragePoint, const Point2D& Point) : SumX(av_AveragePoint.SumX + Point.x), SumY(av_AveragePoint.SumY + Point.y), mv_NbrOfPoints(av_AveragePoint.mv_NbrOfPoints+1) {} operator Point2D() { return Point2D(SumX/mv_NbrOfPoints, SumY/mv_NbrOfPoints); } }; class PointAverage: public std::binary_function<AveragePoint, Point2D, AveragePoint> { public: const AveragePoint operator()(const AveragePoint& avgSoFar, const Point2D& Point) const { return AveragePoint(avgSoFar, Point); } }; std::list<Point2D> PointCont; ... Point2D avg = std::accumulate(PointCont.begin(), PointCont.end(), AveragePoint(), PointAverage()); 9/ 4/02 ga 161 for_each is also faster. 8/24/01 sdm Item 39 My decision to advise readers to make predicates pure functions was based on pragmatic considerations, not on the Standard. In fact, Kreft and Langer argue in their April 2001 column that the Standard allows predicates to have state, though they concede that the problem I describe in this Item does exist in some STL implementations. The Committee ultimately resolved the problem by adding wording to the standard explicitly noting that function objects may be freely copied. For details, consult the Committee's notes on the matter. This resolution means that the advice of the Item should really be more like "Make sure predicates behave well when copied." It also means that that the part of the Item on page 169 (regarding the function anotherBadPredicate) is incorrect, because the fact that there is only one copy of the predicate's state means that it will behave well when copied. 5/19/03 drm 168 drm points out that my claim that "Declaring operator() const in predicate classes is necessary for correct behavior, but it's not sufficient" is too strong, because it would be safe to modify data members that don't affect the outcome of the predicate. Such predicates would be rather odd, however, so to avoid confusing the issue, I have chosen to retain the current wording in the book. 6/16/01 al Item 39 The idea of using remove_if to eliminate the third element from a range is misguided. Implicit in my discussion is the idea that remove_if will examine the elements in the range from the beginning to the end, but this is not required by the Standard and conceptually doesn't make sense. Even if the predicate passed to remove_if could safely have state, the only thing we could reasonably expect from remove_if is that the third element visited would be removed; we wouldn't be able to make any assumptions about which element that would be. For more on this idea, consult the April 2001 column by Klaus Kreft and Angelika Langer, "Unary Predicates in the STL." At the same time, it's worth noting that every implementation of remove_if I know behaves like the one in the book, and there are technical reasons why alternative implementations are unlikely. 9/30/03 mp 188 In the operator() implementation at the top of the page, it might be preferable to write the test this way, return lowVal < val && val < highVal; so that val is both numerically and *physically* between the bottom of the range on the left and the top of the range on the right. mp finds this clearer and also nearer to the mathematical notation "lowVal < val < highVal. (mp attributes this idea to either Steve Maguire's "Writing Solid Code" or "Debugging the Development Process.") 1/13/07 nxd Item 44 This Item also applies to the swap algorithm. (I think it's unfortunate that swap is considered an algorithm, but it is. More details are available in the newsgroup discussion on this topic.) 10/28/01 jep 191 Regarding the widespread use of red-black trees to implement the standard associative containers, jep writes: A perfectly balanced tree is impossible to rebalance after insert/delete in reasonable time. The reason that an RB tree is usually used (I know of no exception other than my AVL implementation) is because that was used in the original. The AVL version outperformed the RB version hands down for searches. With very high dynamics (every search caused either an insert or erase), they were about equal. RB does have a better erase than AVL. I have not found time to try a deterministic skip list yet. Splay-tree and treap in addition to not meeting the required worst case times do not have very good average times either. 10/ 5/05 sdm 200 There are now several entries in the table I would like to change, but I'd have to change the corresponding text more than is practical between printings. In general, table entries correspond to the easiest way to code the tests such that equivalence is used when appropriate. This is explained at the bottom of page 200. However, the second entry in the last column mentions lower_bound instead of equal_range, and, as pointed out on page 201, this is because lower_bound is more efficient than equal_range. As a result, most entries in the table emphasize ease of writing correct code, but at least one emphasizes efficiency of the resulting code. This is inconsistent. If efficiency is to be emphasized (which is likely what I'd do if I were to do it again), the second row would contain these entries in this order, find lower_bound find lower_bound and the third entry in the last row would be "find" instead of equal_range. This is because equal_range requires two logarithmic-time searches, while find and lower_bound require only one. Also, I'd probably change the first entry in the third column from "count" to "find," as I'm no longer convinced that using "count" is a widespread idiom for testing for membership in a set or map. 8/16/01 kh 203 Strictly speaking, the code at the bottom of this page is not standard-conformant, because library implementers are permitted to add extra parameters to library functions, as long as the parameters have default values. (You can read about this matter in Herb Sutter's GOTW #64.) A workaround for such a perverse library implementation would be precisely what Item 46 suggests: use a function object to wrap the call to the library function. 4/13/08 axf 226 axf writes: "You have the link to the ANSI store, but there are two more options today. One is the printed 2003 version from Wiley's, the other is the fact that the current standard drafts are available at the C++ standards web site, and the final wording may very well be posted there as a freely accessible working document. I have a shortcut (via a domain I own) as http://stdcpp.org/, which redirects to the real site at http://www.open-std.org/jtc1/sc22/wg21/. Perhaps you want to mention these sources for information on the C++ standard. The Wiley's books (both C and C++ standard) if someone prefers a fairly priced printed copy, and the standardization committee's site for those who want to follow what is going on." 11/14/01 yd 243-244 yd writes: "I took your advice and turned on the __STL_MEMBER_TEMPLATES flag in the SGI STL configuration. However I was not able to compile, due to a Microsoft bug (Q241949 in the MS knowledge base). MSVC6 supports member templates, but only when they are defined inside the class body. The SGI STL has many such members defined out-of-body. Getting it to compile would require extensive cut-and-paste throughout. I haven't checked STLport, but chances are it has the same problem since it's derived from SGI STL." I know from personal experience that some constructs requiring member templates work with MSVC6 and STLport, so this suggests that STLport has modified the SGI distribution on which it is based to better work with MSVC6. That suggests that STLport's STL may be a better choice than SGI's, at least as regards support for member function templates under MSVC6.
Who's who:
al = Angelika Langer kg = Klaus Gütter mjh = Michael Hawkins wg = Wayne Goertel dp = Derek Price gn = Gabriel Netterdag jw = Jon Webb rd = Ruediger Dreier lz = Leor Zolman ma = Motti Abramsky cc = Charles Cao yd = Yigal Dayan pe = Phil Edwards ib = Ian Bruntlett js = Jim Scheller axg = Adam Gates kl = Laushway Kevin sk = Stefan Kuhlins jk = Jason Kenny mm = Marc Meketon cm = Carl Manaster jdl = Jonathan Low hs = Herb Sutter lfr = Fraser Ross ajf = Albert J. Franklin ss = Stan Sulsky gk = George King sxb = Scott Blachowicz dm = Dave Miller en = Eric Niebler hh = Harold Howe mkk = Mary Kuhner jf = John Fuller kes = Keith Stanley tm = Tim McCarthy ckl = Chan Ki Lok pc = Paolo Carlini apl = Alan Lehotsky jeh = John Hershberger jcj = Jeffrey C. Jacobs imt = Igor Mikolic-Torreira pn = Phillip Ngan sb = Stephan Bergmann wb = Wolfram Burkhardt ras = Robert Allan Schwartz as = Adrian Spermezan jep = John Potter gm = Gareth McCaughan gl = Guillaume Laurent ga = Giulio Agostini yjz = Yingjun Zhang cb = Charles Brockman dg = David Grigsby shh = Seyed H. Haeri kh = Kevlin Henney jr = Johan Rade sp = Sanjay Pattni drm = Doug Morgan hxh = Howard Hinnant mp = Matt Page ja = Jesper Andersen mc = Moshe Cohen jtw = Jing Tao Wang jp = Jim Phillips ag = Andrea Griffini or = Olaf Raeke ab = André Blavier df = Daniel Filip ds = Dan Schmidt tb = Tim Buchowski bww = Bradley White he = Hans Eckardt dxc = David X Callaway gc = Guru Chandar fk = Feliks Kluzniak sk = Sharad Kala ap = Adam Petersen dxm = Declan Moran db = Day Barr nds = Nick de Smith fxs = Shlomi Frank bxr = Bert Rodiers af = Andy Fyfe vxs = Vincent Stojanov mxd = Mark Davis txs = Thomas Schell cmm = Cameron Mac Minn rxp = Randy Parker gxu = Giora Unger cxb = Christos Bellos nxd = Niels Dekker axm = Adam McLaurin abt = Allen B. Taylor cpj = Chris Just dmr = Martin Rottinger dd = Dibyendu Das mxs = Molly Sharp nxh = Neil Henderson ajs = Andrew Savige jxn = Julie Nahil axf = Attila Fehér axa = Amnon Aaronsohn sxv = Subramanian Venkatasubramanian mam = Mark A. McLaughlin rsb = Robert S. Barnes jxb = Jan Bielawski axw = Alexander Weaver bvw = Bart Vandewoestyne cxp = Charlie Page sxl = Sergey Lyskov rxh = Rafael Hamdan
From here you may wish to visit the Amazon Page for Effective STL.