Last week's terrorist attack forced us to postpone THE C++ Seminar, which
was orignally scheduled for this week. The new dates are October 15-17,
and if there's anything that can be considered "good" about the
postponement, it's that we were able to reserve a room that can accommodate
more people this time. After existing registrants are given a chance to
roll over their registrations and people from the wait list are given a
chance to enroll, there are likely to be a dozen or so empty slots. If you
are interested in being able to participate in a hard-core C++ seminar with
me, Herb Sutter, Dan Saks, Steve Dewhurst, and Andrei Alexandrescu, I
encourage you to visit the seminar's home page
(http://www.gotw.ca/cpp_seminar/) to view the schedule and details on how
to register.
I hope to see you at the seminar, where I can promise a certain amount of
fireworks as I attempt to convince my head-in-the-sand compatriots that
namespaces, templates, and exceptions aren't necessarily all they're
cracked up to be...
Scott
Tuesday, September 18, 2001
Friday, September 14, 2001
Updated errata lists; article in CUJ; upcoming seminar reports
Topics this time:
- EC++ and MEC++ Errata Lists have been updated.
- I have an article in the October CUJ.
- Reports from "THE C++ Seminar" to be posted (but not here).
Updated Errata Lists:
I just finished updating the errata lists for Effective C++ and More
Effective C++. (Both books are due for reprints later this month, so the
time was ripe.) New entries to the errata lists are at the end of this
message. The full lists are available at the usual URLs:
EC++: http://www.aristeia.com/BookErrata/ec++2e-errata_frames.html
MEC++: http://www.aristeia.com/BookErrata/mec++-errata_frames.html
Article in the October CUJ:
The October CUJ contains a slightly-modified version of Effective STL's
Item 43, "Prefer Algorithm Calls to Hand-Written Loops." (The article
title is one of the things that is slightly modified compared to the book.)
As an aside, the December CUJ is slated to run ESTL Item 45, but don't
believe it until you see it, because publication plans have been known to
change at the last minute.
Reports from "THE C++ Seminar":
The special C++ Seminar hosted by me, Herb Sutter, Dan Saks, Steve
Dewhurst, and Andrei Alexandrescu runs next Monday-Wednesday. If you're
one of the people who would have liked to attend, but couldn't, or if
you're just curious about what such an event will be like (I am), we plan
to post daily informal summaries to the seminar's mailing list. (They will
NOT be posted to this list). You can sign up for the seminar's mailing
list at http://groups.yahoo.com/group/cpp_seminar/.
Finally, I truly hope that you and yours were not personally affected by
Tuesday's indescribable horrors. Words do not exist for how I feel, so
I'll just say this: I wish you all the best.
Scott
===============================================================================
New Entries for the EC++ Errata List
===============================================================================
DATE DATE
REPORTED WHO PAGES WHAT FIXED
-------- --- ----- ------------------------------------------------ --------
3/ 7/01 das xix "Dave Smallberg" ==> "David Smallberg" 9/10/01
254
! 8/25/00 pm 68 In operator=, "*ptr = *rhs.ptr;" ==> 9/10/01
"ptr = rhs.ptr;" Modify the comment
accordingly.
8/15/00 cb 104 Eliminate the first prose paragraph on this page. 9/10/01
105 (When I originally wrote the paragraph for the
first edition of EC++, the example involved
string objects, not rational numbers, and for
strings, the situation was different. When I
changed the class for the example, I failed to
recognize that the words no longer made sense
for the example.) To avoid too unbalanced a
page, I moved the break between pages 104 and 105.
8/16/00 cb 124 At the end of the 2nd to last sentence on the 9/10/01
page, it would be helpful to xref Item 21's
explanation that the data pointed to by a pointer
in a const object is not automatically const.
! 2/10/00 ic 212 A class declaring no operator& function(s) 9/10/01
cxh 213 does NOT have them implicitly declared. Rather,
245 compilers use the built-in address-of operator
246 whenever "&" is applied to an object of that
type. This behavior, in turn, is technically
not an application of a global operator&
function. Rather, it is a use of a built-in
operator.
I eliminated mention of operator& as an
automatically generated function and adjusted the
index to eliminate entries for the removed
material.
! 4/ 8/01 hs 228 The Standardization Committee has now ruled that 9/10/01
library implementers must declare string as
defined in the Standard, so my comment about
their being allowed to add extra parameters is
incorrect. However, the Standard continues
to forbid you from declaring string yourself.
The advice in this Item stands (#include
<string> instead of trying to declare the string
type yourself), but the rationale for that
advice is no longer valid.
Interesting Comments:
DATE
REPORTED WHO PAGES WHAT
-------- --- ----- -----------------------------------------------------------
8/ 8/00 cb 15 Observes cb:
It appears that the Microsoft Visual C++ 6.0 SP3 compiler
requires the "enum hack" to work. Interesting, since it
is stated that "Unless you're dealing with compilers of
primarily historical interest (i.e., those written before
1995), you shouldn't have to use the enum hack."
It appears that Visual C++ 6 was released in mid-1998.
Sigh.
6/20/01 cbs Items cbs points out that the code in Item 30 isn't thread safe,
sdm 7,8,10 but the problem exists in Items 8 and 10, too. In fact, I
fail to consider thread-safety throughout the book,
something I can argue is excusable only because C++ itself
fails to consider threading issues. You'll see other
comments on how threading interact with my advice in
various places in this errata list. If I ever write a
third edition, I'll be sure to take threading issues into
account.
6/ 5/01 sdm 67 In the prose following the third code example, it's not
technically true that the temporary is const. Rather, the
temporary is an rvalue, and C++ forbids binding references
to rvalues unless they are references to const. This is
not a bug in the book. Rather, it is a deliberate attempt
to spare you from having to know about rvalues, because
they're more confusing than helpful, especially if you know
the rules for rvalues in C. Setting aside technicalities,
the information on this page is accurate in its
essentials.
6/22/01 sdm Item 19 The bulleted summary at the end of this Item no longer
reflects my full thinking on this topic. For an updated
version of the summary as well as an explanation of how and
why things changed, please read my February 2000 href="http://www.cuj.com/" target="_top">C/C++
Users Journal article, href="http://www.cuj.com/articles/2000/0002/0002c/0002c.htm" target="_top">"How
non-member functions improve
encapsulation."
2/19/01 sdm Item 19 When templates enter the picture, things become more
complicated. Compilers must not only perform type
conversions on actual parameters, they must also perform
template type deduction to determine the types of formal
parameters. The end result is that templates for functions
like operator+ should still be non-members, but they need
to be defined as friends inside the class they work with in
order to be instantiated correctly. For details, consult
the February 2000 thread in comp.std.c++ with the title,
href="http://groups.google.com/groups?hl=en&safe=off&threadm=zdv176.950799804%40\
zam475&rnum=1&prev=/groups%3Fas_epq%3Dautomatic%2520conversion%2520with%2520func\
tion%2520templates%26as_ugroup%3Dcomp.std.c%252b%252b%26as_drrb%3Db%26as_mind%3D\
29%26as_minm%3D1%26as_miny%3D2000%26as_maxd%3D5%26as_maxm%3D9%26as_maxy%3D2001%2\
6num%3D100" target="_top">"Automatic conversion with function templates?"
It was
initiated by Bernd Mohr.
9/17/00 ch Item 20 Notes ch:
Objects are state machines. An Object would lose control
of its own states if you allow public data members. This
makes it for instance impossible to implement a typical
Observer Pattern in an object oriented way. The problems
get really nasty for objects with public data members
when living in a multithreaded environment ....
6/11/00 tm 99 In general, it's dangerous for a function to return a
reference to a parameter passed by reference-to-const,
because the parameter may have been bound to a temporary
object that will be destroyed at the end of the call. For
example, consider this use of returnStudent:
Student makeStudent(); // function declaration
const Student& cs = returnStudent(makeStudent());
returnStudent's parameter s is bound to the temporary
object returned from makeStudent. returnStudent then
returns that reference, which is used to initialize another
reference, cs. Unfortunately, once cs is initialized, the
temporary returned from makeStudent is destroyed, and cs is
a dangling reference -- it refers to an object that no
longer exists. (Note the similarity to the problem
discussed on pages 127-128.)
2/27/01 ph Item 23 Once you've resigned yourself to returning a new object
from functions like operator*, you'll naturally look for
ways to make that as cheap as possible. One way to do that
is to return a pointer posing as an object.
The following comment was sent regarding Item 20 of href="http://www.awl.com/cseng/titles/0-201-63371-X/" target="_blank">More
Effective C++, but it's relevant to Item 23 of
Effective
C++, too:
We faced the problem of getting large float and int
arrays from a database. The dimension of the array
depended on the time interval passed as an argument to
the reading method. Clearly, we had to return an object,
and we couldn't rely upon return value optimization
[which is the subject of MEC++ Item 20].
Our solution was to return an auto_ptr<Array<T>
> instead
of an Array<T>. This way, we had the advantage of
returning something as light as a pointer without the
problem of potential memory leaks. The only drawback was
a slightly heavier syntax but it was worth it.
I don't think this is a solution for the method operator*
that you used in item 20 but many other methods that have
to return large objects may benefit from it.
===============================================================================
New Entries for the MEC++ Errata List
===============================================================================
DATE DATE
REPORTED WHO PAGES WHAT FIXED
-------- --- ----- ------------------------------------------------ --------
3/30/01 sdm 2 Material in the book is based on the final C++
Standard, not the DIS.
9/ 6/00 bp 33 In accord with my advice in Item 21 of 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" ==>
"initialization of".
! 8/15/00 wcm 142 For consistency with the changes I made on
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.
Interesting Comments:
DATE
REPORTED WHO PAGES WHAT
-------- --- ----- -----------------------------------------------------------
7/31/00 cw 208ff Notes cw:
While href="http://www.aristeia.com/BookErrata/M29Source.html"
target="_blank">exploring your reference counting code, I realized
that there is no method allowing a user of the RCIPtr
class to mark the CountHolder unshareable. I believe such
a method is essential to the correct operation of the
RCIPtr when a user is confronted with making a some one
else's class reference counted and that class has methods
which return references to the the internal parts of the
class.
In your widget example, if there were a method
int& Widget::getThat(), the corresponding RCWidget method
would have to make a call to a RCIPtr::markUnshareable()
method that would call the RCObject::markUnshareable()
method. This would prevent the int reference from being
used to alter a widget that is held by more than one
RCWidget.
http://www.aristeia.com/BookErrata/M29Source.html
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.
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... . In
this scenario, when calling template functions that take
complex (e.g. conj() et al) with a returned proxy, the
proxy is not converted to a complex but instead a
template argument deduction failure results.
For further information on this observation, look up the
thread, href="http://groups.google.com/groups?hl=en&threadm=5jq51o%2479g%40netlab.cs.rpi\
.edu&rnum=1&prev=/groups%3Fas_epq%3Done%2520problem%2520with%2520the%2520use%252\
0of%2520proxies%26as_ugroup%3Dcomp.lang.c%252b%252b.moderated%26as_drrb%3Db%26as\
_mind%3D29%26as_minm%3D3%26as_miny%3D1997%26as_maxd%3D13%26as_maxm%3D9%26as_maxy\
%3D1997">"lvalue/rvalue, non-const/const" initiated by Daniel
Hempel on April 21, 1997.
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 href="http://www.awl.com/cseng/titles/0-201-70431-5/">Modern C++
Design. It's the most
thorough and up-to-date examination of the topic that I know
of.
- EC++ and MEC++ Errata Lists have been updated.
- I have an article in the October CUJ.
- Reports from "THE C++ Seminar" to be posted (but not here).
Updated Errata Lists:
I just finished updating the errata lists for Effective C++ and More
Effective C++. (Both books are due for reprints later this month, so the
time was ripe.) New entries to the errata lists are at the end of this
message. The full lists are available at the usual URLs:
EC++: http://www.aristeia.com/BookErrata/ec++2e-errata_frames.html
MEC++: http://www.aristeia.com/BookErrata/mec++-errata_frames.html
Article in the October CUJ:
The October CUJ contains a slightly-modified version of Effective STL's
Item 43, "Prefer Algorithm Calls to Hand-Written Loops." (The article
title is one of the things that is slightly modified compared to the book.)
As an aside, the December CUJ is slated to run ESTL Item 45, but don't
believe it until you see it, because publication plans have been known to
change at the last minute.
Reports from "THE C++ Seminar":
The special C++ Seminar hosted by me, Herb Sutter, Dan Saks, Steve
Dewhurst, and Andrei Alexandrescu runs next Monday-Wednesday. If you're
one of the people who would have liked to attend, but couldn't, or if
you're just curious about what such an event will be like (I am), we plan
to post daily informal summaries to the seminar's mailing list. (They will
NOT be posted to this list). You can sign up for the seminar's mailing
list at http://groups.yahoo.com/group/cpp_seminar/.
Finally, I truly hope that you and yours were not personally affected by
Tuesday's indescribable horrors. Words do not exist for how I feel, so
I'll just say this: I wish you all the best.
Scott
===============================================================================
New Entries for the EC++ Errata List
===============================================================================
DATE DATE
REPORTED WHO PAGES WHAT FIXED
-------- --- ----- ------------------------------------------------ --------
3/ 7/01 das xix "Dave Smallberg" ==> "David Smallberg" 9/10/01
254
! 8/25/00 pm 68 In operator=, "*ptr = *rhs.ptr;" ==> 9/10/01
"ptr = rhs.ptr;" Modify the comment
accordingly.
8/15/00 cb 104 Eliminate the first prose paragraph on this page. 9/10/01
105 (When I originally wrote the paragraph for the
first edition of EC++, the example involved
string objects, not rational numbers, and for
strings, the situation was different. When I
changed the class for the example, I failed to
recognize that the words no longer made sense
for the example.) To avoid too unbalanced a
page, I moved the break between pages 104 and 105.
8/16/00 cb 124 At the end of the 2nd to last sentence on the 9/10/01
page, it would be helpful to xref Item 21's
explanation that the data pointed to by a pointer
in a const object is not automatically const.
! 2/10/00 ic 212 A class declaring no operator& function(s) 9/10/01
cxh 213 does NOT have them implicitly declared. Rather,
245 compilers use the built-in address-of operator
246 whenever "&" is applied to an object of that
type. This behavior, in turn, is technically
not an application of a global operator&
function. Rather, it is a use of a built-in
operator.
I eliminated mention of operator& as an
automatically generated function and adjusted the
index to eliminate entries for the removed
material.
! 4/ 8/01 hs 228 The Standardization Committee has now ruled that 9/10/01
library implementers must declare string as
defined in the Standard, so my comment about
their being allowed to add extra parameters is
incorrect. However, the Standard continues
to forbid you from declaring string yourself.
The advice in this Item stands (#include
<string> instead of trying to declare the string
type yourself), but the rationale for that
advice is no longer valid.
Interesting Comments:
DATE
REPORTED WHO PAGES WHAT
-------- --- ----- -----------------------------------------------------------
8/ 8/00 cb 15 Observes cb:
It appears that the Microsoft Visual C++ 6.0 SP3 compiler
requires the "enum hack" to work. Interesting, since it
is stated that "Unless you're dealing with compilers of
primarily historical interest (i.e., those written before
1995), you shouldn't have to use the enum hack."
It appears that Visual C++ 6 was released in mid-1998.
Sigh.
6/20/01 cbs Items cbs points out that the code in Item 30 isn't thread safe,
sdm 7,8,10 but the problem exists in Items 8 and 10, too. In fact, I
fail to consider thread-safety throughout the book,
something I can argue is excusable only because C++ itself
fails to consider threading issues. You'll see other
comments on how threading interact with my advice in
various places in this errata list. If I ever write a
third edition, I'll be sure to take threading issues into
account.
6/ 5/01 sdm 67 In the prose following the third code example, it's not
technically true that the temporary is const. Rather, the
temporary is an rvalue, and C++ forbids binding references
to rvalues unless they are references to const. This is
not a bug in the book. Rather, it is a deliberate attempt
to spare you from having to know about rvalues, because
they're more confusing than helpful, especially if you know
the rules for rvalues in C. Setting aside technicalities,
the information on this page is accurate in its
essentials.
6/22/01 sdm Item 19 The bulleted summary at the end of this Item no longer
reflects my full thinking on this topic. For an updated
version of the summary as well as an explanation of how and
why things changed, please read my February 2000 href="http://www.cuj.com/" target="_top">C/C++
Users Journal article, href="http://www.cuj.com/articles/2000/0002/0002c/0002c.htm" target="_top">"How
non-member functions improve
encapsulation."
2/19/01 sdm Item 19 When templates enter the picture, things become more
complicated. Compilers must not only perform type
conversions on actual parameters, they must also perform
template type deduction to determine the types of formal
parameters. The end result is that templates for functions
like operator+ should still be non-members, but they need
to be defined as friends inside the class they work with in
order to be instantiated correctly. For details, consult
the February 2000 thread in comp.std.c++ with the title,
href="http://groups.google.com/groups?hl=en&safe=off&threadm=zdv176.950799804%40\
zam475&rnum=1&prev=/groups%3Fas_epq%3Dautomatic%2520conversion%2520with%2520func\
tion%2520templates%26as_ugroup%3Dcomp.std.c%252b%252b%26as_drrb%3Db%26as_mind%3D\
29%26as_minm%3D1%26as_miny%3D2000%26as_maxd%3D5%26as_maxm%3D9%26as_maxy%3D2001%2\
6num%3D100" target="_top">"Automatic conversion with function templates?"
It was
initiated by Bernd Mohr.
9/17/00 ch Item 20 Notes ch:
Objects are state machines. An Object would lose control
of its own states if you allow public data members. This
makes it for instance impossible to implement a typical
Observer Pattern in an object oriented way. The problems
get really nasty for objects with public data members
when living in a multithreaded environment ....
6/11/00 tm 99 In general, it's dangerous for a function to return a
reference to a parameter passed by reference-to-const,
because the parameter may have been bound to a temporary
object that will be destroyed at the end of the call. For
example, consider this use of returnStudent:
Student makeStudent(); // function declaration
const Student& cs = returnStudent(makeStudent());
returnStudent's parameter s is bound to the temporary
object returned from makeStudent. returnStudent then
returns that reference, which is used to initialize another
reference, cs. Unfortunately, once cs is initialized, the
temporary returned from makeStudent is destroyed, and cs is
a dangling reference -- it refers to an object that no
longer exists. (Note the similarity to the problem
discussed on pages 127-128.)
2/27/01 ph Item 23 Once you've resigned yourself to returning a new object
from functions like operator*, you'll naturally look for
ways to make that as cheap as possible. One way to do that
is to return a pointer posing as an object.
The following comment was sent regarding Item 20 of href="http://www.awl.com/cseng/titles/0-201-63371-X/" target="_blank">More
Effective C++, but it's relevant to Item 23 of
Effective
C++, too:
We faced the problem of getting large float and int
arrays from a database. The dimension of the array
depended on the time interval passed as an argument to
the reading method. Clearly, we had to return an object,
and we couldn't rely upon return value optimization
[which is the subject of MEC++ Item 20].
Our solution was to return an auto_ptr<Array<T>
> instead
of an Array<T>. This way, we had the advantage of
returning something as light as a pointer without the
problem of potential memory leaks. The only drawback was
a slightly heavier syntax but it was worth it.
I don't think this is a solution for the method operator*
that you used in item 20 but many other methods that have
to return large objects may benefit from it.
===============================================================================
New Entries for the MEC++ Errata List
===============================================================================
DATE DATE
REPORTED WHO PAGES WHAT FIXED
-------- --- ----- ------------------------------------------------ --------
3/30/01 sdm 2 Material in the book is based on the final C++
Standard, not the DIS.
9/ 6/00 bp 33 In accord with my advice in Item 21 of 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" ==>
"initialization of".
! 8/15/00 wcm 142 For consistency with the changes I made on
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.
Interesting Comments:
DATE
REPORTED WHO PAGES WHAT
-------- --- ----- -----------------------------------------------------------
7/31/00 cw 208ff Notes cw:
While href="http://www.aristeia.com/BookErrata/M29Source.html"
target="_blank">exploring your reference counting code, I realized
that there is no method allowing a user of the RCIPtr
class to mark the CountHolder unshareable. I believe such
a method is essential to the correct operation of the
RCIPtr when a user is confronted with making a some one
else's class reference counted and that class has methods
which return references to the the internal parts of the
class.
In your widget example, if there were a method
int& Widget::getThat(), the corresponding RCWidget method
would have to make a call to a RCIPtr::markUnshareable()
method that would call the RCObject::markUnshareable()
method. This would prevent the int reference from being
used to alter a widget that is held by more than one
RCWidget.
http://www.aristeia.com/BookErrata/M29Source.html
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.
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
this scenario, when calling template functions that take
complex
proxy is not converted to a complex
template argument deduction failure results.
For further information on this observation, look up the
thread, href="http://groups.google.com/groups?hl=en&threadm=5jq51o%2479g%40netlab.cs.rpi\
.edu&rnum=1&prev=/groups%3Fas_epq%3Done%2520problem%2520with%2520the%2520use%252\
0of%2520proxies%26as_ugroup%3Dcomp.lang.c%252b%252b.moderated%26as_drrb%3Db%26as\
_mind%3D29%26as_minm%3D3%26as_miny%3D1997%26as_maxd%3D13%26as_maxm%3D9%26as_maxy\
%3D1997">"lvalue/rvalue, non-const/const" initiated by Daniel
Hempel on April 21, 1997.
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 href="http://www.awl.com/cseng/titles/0-201-70431-5/">Modern C++
Design. It's the most
thorough and up-to-date examination of the topic that I know
of.
Monday, September 3, 2001
Updated ESTL Errata; Powell's Talk Reminder
Two quick things:
- I've updated the ESTL errata list. New entries are below.
- Reminder: I'm speaking at Powells in Portland this Thursday.
Updated ESTL Errata List:
I've received a number of interesting bug reports and other comments on
ESTL since I last updated the errata list, so I've added the new stuff to
the list. You'll find the updated list in its usual spot at
http://www.aristeia.com/BookErrata/estl1e-errata_frames.html. The new
entries are listed below in the half-baked form I use internally for
keeping track of new errata.
Talk at Powell's this Thursday:
This Thursday night I'll be doing a C++/STL Q&A at Powell's Technical
bookstore at 7:00 PM. For details, consult my earlier mailing on this
topic (http://groups.yahoo.com/group/scott_meyers/message/27). I hope to
see you there!
Scott
DATE DATE
REPORTED WHO PAGES WHAT FIXED
-------- --- ----- ------------------------------------------------ --------
8/31/01 ds iv "Dr. Suess" ==> "Dr. Seuss" (twice).
8/ 4/01 dg 18-19 Once the typedef WidgetContainer is introduced,
the variable vw should be renamed cw to reflect
the new, more abstract, type name.
8/23/01 sdm Item 4 Clarify that of the three list::splice functions,
only one requires linear complexity. The other
two can run in constant time and can allow size to
run in constant time.
8/17/01 sdm 47 Omit from para 2 the advice to treat list like
a sequence container. Based on a discussion with
jep, I'm now less certain that that convention is
as widespread as I'd thought.
! 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."
! 8/23/01 ja 78-79 When string implementations use reference
counting, the swap trick 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);
8/23/01 ja 79 The last paragraph of Item 17 is true, but it
doesn't matter in this context, because the swap
is with a temporary object that is destroyed at
the end of the statement. As a result, all
iterators, pointers, and references into the
"shrunk-to-fit" string have been invalidated.
I'll omit this paragraph from future printings
(and I'll try to remember to check the index to
see if it gets anything from this paragaph).
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. Include a warning in
this Item and xref the example on pg. 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 sdm 92 Eliminate the second-to-last sentence on this
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.)
! 8/22/01 jep Item 22 Shortly after the book was published, the Committee
decided that elements of sets/multisets should not be
modifiable without a cast, so the second code example
on page 96 is now invalid. To change a set/multiset
element in place, use the const_cast technique shown
on page 98. If you don't need in-place modification,
the five-step process described on pp. 99-100
continues to be safe and portable.
! 8/22/01 jep 104 In the lines after the calls to lower_bound, the
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/20/01 ag 108 The analysis for the cost of the call to insert is
incorrect, because it overlooks that the pair
created in the insert call is a temporary that
will ultimately be used to copy construct the pair
stored in the map. Because the temporary pair
contains a Widget, a temporary Widget is
constructed and destroyed. In practice, ag
observed that "the difference between the two
methods is only that in the operator[] form,
there's the extra call to the assignment operator
specialized for a double."
ag has demonstrated that operator[] could be
implemented much more efficiently than insert, but
the Standard is unfortunately worded in a way that
makes such implementations illegal. In the
future, this wording may be changed, or
implementers may choose to ignore it.
All things considered, the conclusion that insert
is more efficient than operator[] when adding new
elements to a map is not as reliable as I thought
when I wrote the book. In the immortal words of
Nathan Myers, "if it matters, measure."
8/ 4/01 dg 136 In last para, "which reorders element" ==>
"which reorders elements".
8/23/01 sdm 144 In the lower diagram, non-code text in
"remove_if's return value" should be in text font.
! 8/16/01 kh 159 In the call to accumulate at the top of the page,
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.
8/ 3/01 sdm 160 In the para following the code, there should be
no line break between "paragraph" and "2".
8/ 4/01 dg 162 The use of the term "components" in the 1st para
is confusing, because I never define that term.
Reword. (In general, I use "component" in this
book to mean "something in the STL.")
8/21/01 sdm 165 BPFCImpl should inherit from unary_function.
8/24/01 sdm 169 Practically speaking, anotherBadPredicate isn't as
bad as the function objects generated by
BadPredicate, because there is only one copy of
its state. As a result, anotherBadPredicate is
likely to behave as expected when passed to
remove_if or any other algorithm. (But see below
for "Interesting Comments" on Item 39.)
8/18/01 sp 187 Once in a code example on each page,
188 "vector<int> iterator" ==>
189 "vector<int>::iterator".
8/23/01 sdm 200 In the entry for equal_range in the next-to-last
row of the table, add "(followed by distance)".
Make the same change to this table on the book's
inside front cover.
8/30/01 ab 211 At end of 2nd para, "Another STL platform I uses..."
==>
"Another STL platform I use..."
8/ 4/01 dg 221 In 2nd para, "do fire up" ==> "do is fire up".
8/28/01 jtw 228 A more reliable URL for [27] is
http://www.research.att.com\
/~bs/stack_cat.pdf.
Interesting Comments:
DATE
REPORTED WHO PAGES WHAT
-------- --- ----- -----------------------------------------------------------
7/28/01 jep Item 9 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.
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, 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.
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 book's 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.
8/20/01 ag 110-111 Write 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_value: one in lower_bound, one in
key_comp and another one in insert.
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.
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 CUJ 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 is aware of the problem,
but from what I can tell, they are leaning towards
modifying the Standard to require that predicates be pure
functions. If they do, my advice will conform to the
Standard at that point. To follow the Committee's
deliberations on this matter, monitor the status of
Library
Working Group Issue #92.
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.
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.
- I've updated the ESTL errata list. New entries are below.
- Reminder: I'm speaking at Powells in Portland this Thursday.
Updated ESTL Errata List:
I've received a number of interesting bug reports and other comments on
ESTL since I last updated the errata list, so I've added the new stuff to
the list. You'll find the updated list in its usual spot at
http://www.aristeia.com/BookErrata/estl1e-errata_frames.html. The new
entries are listed below in the half-baked form I use internally for
keeping track of new errata.
Talk at Powell's this Thursday:
This Thursday night I'll be doing a C++/STL Q&A at Powell's Technical
bookstore at 7:00 PM. For details, consult my earlier mailing on this
topic (http://groups.yahoo.com/group/scott_meyers/message/27). I hope to
see you there!
Scott
DATE DATE
REPORTED WHO PAGES WHAT FIXED
-------- --- ----- ------------------------------------------------ --------
8/31/01 ds iv "Dr. Suess" ==> "Dr. Seuss" (twice).
8/ 4/01 dg 18-19 Once the typedef WidgetContainer is introduced,
the variable vw should be renamed cw to reflect
the new, more abstract, type name.
8/23/01 sdm Item 4 Clarify that of the three list::splice functions,
only one requires linear complexity. The other
two can run in constant time and can allow size to
run in constant time.
8/17/01 sdm 47 Omit from para 2 the advice to treat list like
a sequence container. Based on a discussion with
jep, I'm now less certain that that convention is
as widespread as I'd thought.
! 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."
! 8/23/01 ja 78-79 When string implementations use reference
counting, the swap trick 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);
8/23/01 ja 79 The last paragraph of Item 17 is true, but it
doesn't matter in this context, because the swap
is with a temporary object that is destroyed at
the end of the statement. As a result, all
iterators, pointers, and references into the
"shrunk-to-fit" string have been invalidated.
I'll omit this paragraph from future printings
(and I'll try to remember to check the index to
see if it gets anything from this paragaph).
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. Include a warning in
this Item and xref the example on pg. 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 sdm 92 Eliminate the second-to-last sentence on this
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.)
! 8/22/01 jep Item 22 Shortly after the book was published, the Committee
decided that elements of sets/multisets should not be
modifiable without a cast, so the second code example
on page 96 is now invalid. To change a set/multiset
element in place, use the const_cast technique shown
on page 98. If you don't need in-place modification,
the five-step process described on pp. 99-100
continues to be safe and portable.
! 8/22/01 jep 104 In the lines after the calls to lower_bound, the
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/20/01 ag 108 The analysis for the cost of the call to insert is
incorrect, because it overlooks that the pair
created in the insert call is a temporary that
will ultimately be used to copy construct the pair
stored in the map. Because the temporary pair
contains a Widget, a temporary Widget is
constructed and destroyed. In practice, ag
observed that "the difference between the two
methods is only that in the operator[] form,
there's the extra call to the assignment operator
specialized for a double."
ag has demonstrated that operator[] could be
implemented much more efficiently than insert, but
the Standard is unfortunately worded in a way that
makes such implementations illegal. In the
future, this wording may be changed, or
implementers may choose to ignore it.
All things considered, the conclusion that insert
is more efficient than operator[] when adding new
elements to a map is not as reliable as I thought
when I wrote the book. In the immortal words of
Nathan Myers, "if it matters, measure."
8/ 4/01 dg 136 In last para, "which reorders element" ==>
"which reorders elements".
8/23/01 sdm 144 In the lower diagram, non-code text in
"remove_if's return value" should be in text font.
! 8/16/01 kh 159 In the call to accumulate at the top of the page,
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.
8/ 3/01 sdm 160 In the para following the code, there should be
no line break between "paragraph" and "2".
8/ 4/01 dg 162 The use of the term "components" in the 1st para
is confusing, because I never define that term.
Reword. (In general, I use "component" in this
book to mean "something in the STL.")
8/21/01 sdm 165 BPFCImpl should inherit from unary_function.
8/24/01 sdm 169 Practically speaking, anotherBadPredicate isn't as
bad as the function objects generated by
BadPredicate, because there is only one copy of
its state. As a result, anotherBadPredicate is
likely to behave as expected when passed to
remove_if or any other algorithm. (But see below
for "Interesting Comments" on Item 39.)
8/18/01 sp 187 Once in a code example on each page,
188 "vector<int> iterator" ==>
189 "vector<int>::iterator".
8/23/01 sdm 200 In the entry for equal_range in the next-to-last
row of the table, add "(followed by distance)".
Make the same change to this table on the book's
inside front cover.
8/30/01 ab 211 At end of 2nd para, "Another STL platform I uses..."
==>
"Another STL platform I use..."
8/ 4/01 dg 221 In 2nd para, "do fire up" ==> "do is fire up".
8/28/01 jtw 228 A more reliable URL for [27] is
http://www.research.att.com\
/~bs/stack_cat.pdf.
Interesting Comments:
DATE
REPORTED WHO PAGES WHAT
-------- --- ----- -----------------------------------------------------------
7/28/01 jep Item 9 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.
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
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.
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 book's 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.
8/20/01 ag 110-111 Write 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_value: one in lower_bound, one in
key_comp and another one in insert.
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.
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 CUJ 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 is aware of the problem,
but from what I can tell, they are leaning towards
modifying the Standard to require that predicates be pure
functions. If they do, my advice will conform to the
Standard at that point. To follow the Committee's
deliberations on this matter, monitor the status of
Library
Working Group Issue #92.
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.
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.
Subscribe to:
Posts (Atom)