Practical Solutions for Real-Life Programming

Home Reviews Errata Links Blog Contact

Errata

Updated: 8th November 2009
This section is comprised of any changes or concerns related to Imperfect C++ since its publishing. You can find listed missing material (from the CD), enhancements to the book's content, code errata / bug reports, typos, and other related information. Click through to Amazon.com
Date Author Section Details Type
23rd March 2005 Jonathan Small page 112

I'm a little way through your new book, and have to say I think its pretty good. Just a quick comment on p112 about the vtbl layout. I'm a COM veteran, so I've had a reasonable amount of experience in it.

The gcc layout is different because of the different style of 'offset correction' techniques used. That is the correction of the 'this' pointer when it gets passed to the function. gcc 2.9x and older (non MS) compilers use a technique where the offset is placed in the vtable next to the functions address. Thus when the function is called the objects pointer passed in is corrected by this offset, before the function is actually called.

In the case of VC + later gcc compilers, the technique used is function 'thunking' where a new function is created which corrects the pointer before the base classes function is called (now with the correct 'this'). The technique is known as 'vtable thunking'.

To illustrate the problem:

  struct IA
  {
    virtual void __stdcall DoA() = 0;
  };

  struct IB:public IA
  {
    virtual void __stdcall DoB() = 0;
  }

  struct CBase
    :public IA
  {
    /* override */void __stdcall DoA() { printf("CBase::DoA\n"); }
  }

  struct CDerived
    : public IB
    , public CBase
  {
    /* override */void __stdcall DoA() { printf("CDerived::DoA\n"); }
    /* override */void __stdcall DoB() { printf("CDerived::DoB\n"); }
  }

  int main(int,char *[])
  {
    CDerived der;
    IA *aptr = static_cast<CBase *>(&der);
    IA *bptr = static_cast<IB *>(&der);
  }

In this situation both aptr + bptr point to a IA interface pointer, but they are different IA interface vtables. So that a call to aptr is correctly routed to CDerived's DoA() function the 'this' pointer passed to the call is corrected so that it when its passed into CDerived's DoA() the this pointer is correctly set.

And in this case if you looked at the gcc2.9x vtable you would see different numbers for v3 and v4 (from your example) which would make this correction.

Ie in gcc it is the callers responsibility to fix up this. With VC and later compilers the callee does the fix up, through a generated/invisible 'thunking' function. This can be seen/explained via the disassembly more simply :)

Comment
5th November 2006 Rupert Kittinger page 138; section 10.2.2

C: I would like to comment on the spin mutex section (10.2.2). I think this class is not really "spinning" because of the call to sched_yield(). In all other implementations I have seen, a spinlock basically loops until the locking succeeds. The idea is that if the resource is only locked for a very short time, busy looping is cheaper than a context switch. So spinlocks may be very effective especially when there is a lot of contention. (Needless to say, this only makes sense on multiprocessor machines!)

A: You make a good point. I've updated the STLSoft spin_mutex class(es), so that it is now a class template - spin_mutex_base - that takes a policy class that determines whether the spin incorporates a yield or not. There are two specialisations typedef'd: spin_mutex_no_yield and spin_mutex_yield.

The spin_mutex class is now a typedef to spin_mutex_no_yield, unless STLSOFT_OLD_SPIN_MUTEX_BEHAVIOUR is #define'd, in which case it's a typedef to spin_mutex_yield.

These changes are available from STLSoft 1.9.1. beta 29 or later..

Comment
23rd June 2005 Juan Antonio Zaratiegui Vallecillo page 209; listing 14.1

I have tried some of your samples, both in Borland 5.6.4 and GCC 3.2, and there is a problem with page 209, listing 14.1, which fails unexpectedly on GCC. I had to add the next overload:

  void reject_subscript_operator(void * const)
  {}

because GCC would fail to use the function for

  reject_subscript_operator(pv);

instantiating instead the template. I don't know which of those compilers is following the Standard rules for resolution, as there is a cv-qualifier implied, and C++ standard is pretty difficult to understand in such themes. Or are we in front of unspecified/implementation-specific material?

Comment
17th September 2004 Matthew Wilson page 521; section 34.4

Since the writing of the book, the refinement of the Range concept has continued, and a new category - the Indirect Range - has been introduced which abstracts callback enumeration APIs. See www.rangelib.org for details. The new category is also discussed in the article "Ranges, part 1: Concepts and Implementation" in the October 2004 issue of C/C++ User's Journal.

Enhancement
1st October 2004 Sam Saariste page 510; section 34.2.1

Sam makes the following important point:

"Use of

  std::for_each(&ari[0], &ari[10], print_int);

is incorrect. Even thought it is likely to work for any compiler you will ever use, it is still ill-formed. It should be

  std::for_each(&ari[0], &ari[0] + 10, print_int);

The same applies for

  std::for_each(&ari[0], &ari[dimensionof(ari)], print_int);

which should be

  std::for_each(&ari[0], &ari[0] + dimensionof(ari), print_int);

and for

  std::for_each(&ar[0], &ar[N], f);

which should be

  std::for_each(&ar[0], &ar[0] + N, f);.

Erratum
17th September 2004 Matthew Wilson page 411; section 25.1.3

This technique, from Chapter 25, was presented to the world in the "Fast, Non-intrusive String Concatenation" article in the June 2004 issue of C/C++ Users Journal. Thanks to a reader - Sean Kelly - for pointing out that the technique assumes that the parameterising string class stores its character data contiguously. That should be ok in practice, since we know of no string class - std or otherwise - that does not do so. Nonetheless, it's a bug, and has been addressed in version 1.8.1 release of the STLSoft libraries.

Erratum
23rd March 2005 Jonathan Small page 126; section 9.2.1

It says a 'dynamic library is complete'. Jonathan says that this is "not necessarily so - you can have imports and exports within a dll - such that the dll has to have functions imported from it from the executable or another dll. I have used this on a dll system loading a device driver where the dll, had to use standard library calls, and they only worked with the standard library functions linked into the executable (as they were correctly set up prior to main). This was a while ago using Watcom/DOS but the point is the Dll standard supported imports/exports. I dunno if its used much with Win32 if at all.".

While I certainly take the point that a dynamic library may (and in fact almost always does) depend on symbols in other dynamic libraries, I'm not confident that one can depend on symbols defined inside the loading process; naturally this is a perfectly normal and well-used technique for static libraries. Certainly I'm pretty sure that one cannot do this with Win32 DLLs. I'd be interested to hear from anyone whether this is possible under UNIX/Linux.

Erratum
21st January 2007 Thomas Schell page 298

the code illustrating the use of stlsoft::true_typedef with int should read


true_typedef<int, . . .> i1(1000);
int i2(1001);
true_typedef<int, . . .> i3(i2);
 

i1 <<= 2;
i1 = -i3;
i3 = i2 + i3;

Erratum
25th July 2005 Dirk Bonekaemper page 212; section 14.3

I've got a comment on your dimensionof() macro (14.3). I liked it a lot and reimplemented our version of dimensionof() for all compilers that supported the syntax. Unfortunately it bombed in the wrong place. The situation boils down to:

  void f()
  {
    static const struct { int n; int m; } a[] = {{1,2},{3,4}};
    const int size = dimensionof(a);
  }

This refuses to compile as template parameters must have external linkage.

I don't see a clean solution except rewriting the code to use a type with external linkage. But as not all of our compilers support namespaces, it would mean inventing a suitably ugly typename to prevent nameclashes. (So, for now, I commented out the new version.)

I guess this caveat should be mentioned in the errata.

Erratum
4th May 2005 Ike Naar page xxix

In the definition of 'value type' on page xxix, it is said that "Equality (and inequality) is reflexive, symmetric, and transitive". Inequality is not reflexive or transitive.

Erratum
17th September 2004 Matthew Wilson page 211; section 14.3

There's a problem with the use of the dimensionof() construct on arrays, when the type of the array is a locally defined struct/class. This is due to the restrictions on linkage of template parameterising types, as is discussed in Chapter 34.

The solution in the STLSoft libraries is pretty much a hack at this point. The stlsoft_num_elements() construct, which is equivalent to the dimensionof construct, uses a helper macro, called stlsoft_num_elements_() which implements that normal, "C", approach using sizeof(x) / sizeof(0[x]). It's hardly pretty, or unambiguous, however, so a better named macro is planned in the near future.

Erratum
6th September 2006 James Widman page 359; section 20.7

the sentence "The first using declaration is necessary because LSA_UNICODE_STRING type is defined in the global namespace, so Koenig lookup does not apply." should instead read "The first using-declaration is necessary because LSA_UNICODE_STRING is defined in the global namespace, and when Koenig Lookup goes searching there it won't find anything."

Erratum
15th January 2007 Thomas Schell page 219; listing 14.5

the statement

  process_array(apb, 10);

should read

  process_array(apb, dimensionof (apb));

Erratum
22nd March 2005 Will Trobaugh page 289; section 18.2.2; listing 18.4

Would you show me a small example of how the returning of the parameter f, where f is a caller-supplied function that is applied to elements of parameter c, would be used?

Thanks for taking the trouble to write to me.

The practice of returning a function object, by value, from an algorithm to which its been passed is widely followed in STL. One important reason is so that one can chain operations succinctly. Passing, and returning, by value is well founded in order to equally support passing function pointers and function object instances.

So, I wrote the for_all_postinc() to return f to follow this convention.

As for an example, I guess one could use it as follows:

  std::vector<int>  vi = ...;
  std::list<int>    li = ...;

  for_all_postinc(vi, for_all_postinc(li, some_function));

The advantage would be where the function object has a non-default constructor, so it saves the coder from having the potentially maintenance-fragile situation of specifying the same thing twice. It also, perhaps, affords the compiler better optimisation opportunity.

Hope that helps.

Question
29th August 2005 Markus Elfring page 215; listing 14.3

Q: The purpose of the parameter size is unclear for me. It seems that it is not used in the body of the first function make_array_proxy().

A: The first make_array_proxy() invokes the first array_proxy constructor, so there's no need to explicitly specify the size. The compiler "sees" an array (rather than a pointer) inside this function as well as outside.

Question
29th August 2005 Markus Elfring page 243

Q: Did you consider an alternate code structure, such as the following?

...
}
else
{
  return unknown;
}
...

A: I think the reason I did it as shown was that the strcmp() tests were all in a clearly separate section, denoted by the extra indentation.

It could just as easily be as you say, but that's just not my style.

Question
29th August 2005 Markus Elfring page 251

Q: Which wording do you prefer: "multi threaded" or "multi-threaded"?

A: I think I prefer the latter, but what I prefer most of all is to be consistent. ;)

Question / Typo
23rd March 2005 Rajanikanth Jammalamadaka page 521; footnote 7

Instead of:
  "John was also a one of the reviewers for this book"
it should read:
  "John was also one of the reviewers for this book"

Typo
13th September 2005 Martin Moene, Thomas Schell page 535

the phrase "..., but the friendship declaration means that it can be altered by Rectangle."should read "..., but the friendship declaration means that it can be altered by LinkedList."

Typo
5th September 2005 Martin Moene, Steven Allan Tague page 522; table 34.2

the phrase "Evaluates to true if r has reached its end condition, false otherwise" should instead read "Evaluates to true if r has not reached its end condition, false otherwise"

Typo
4th September 2005 Martin Moene page 495

the phrase "Not that I'm not saying that the approach of multi_array is wrong, ..." should instead read "I'm not saying that the approach of multi_array is wrong, ..."

Typo
4th September 2005 Martin Moene, Thomas Schell page 484

the phrase "But remember that auto_buffer does support non-POD types, and ..." should instead read "But remember that auto_buffer does not support non-POD types, and ..."

Typo
4th September 2005 Martin Moene page 479-480; listing 32.2

the template argument SPACE is erroneously specified as space

Typo
4th September 2005 Martin Moene page 479; listing 32.1

the template argument SPACE is erroneously specified as space

Typo
4th September 2005 Martin Moene, Thomas Schell page 465; listing 31.6

listing should read

 
PCAChar LongToStringA(LONG value)
{
  const size_t I2S_LIMIT = 0x7f;
  TssValue tssvalue = Tss_GetSlotValue(sh_hkeyA);
  PAChar buffer;
  if(0 == tssvalue)
  {
    tssvalue = (TssValue)Mem_Alloc_NoTrack(sizeof(AChar) * (1 + I2S_LIMIT)));
    . . .
    Tss_SetSlotValue(sh_hkeyA, tssvalue, NULL);
  }
  buffer = SyCastRaw(PAChar, tssvalue);
  return integer_to_string(buffer, 1 + I2S_LIMIT, value);
}

Typo
4th September 2005 Martin Moene page 441; listing 28.1

in the copy-assignment constructor member initializer list m_monitorFN should read m_monitor

Typo
4th September 2005 Martin Moene page 430; listing 26.5

argument p in

  return static_cast(p);

and

  return static_cast(p);

should be m_p

Typo
4th September 2005 Martin Moene page 410; section 25.1.2

in the phrase "... concatenation seeding (see section 24.4) ...", 24.4 should read 25.4

Typo
4th September 2005 Martin Moene page 376; section 22.1

in the phrase "... the well-known C+ mechanism ...", C+ should read C++

Typo
4th September 2005 Martin Moene page 346; section 20.3

in the phrase "... shim general case -- the second in the list above -- is defined ...", second should be first

Typo
4th September 2005 Martin Moene page 338; listing 19.20

The member types pointer_type and reference_type should be pointer and reference, respectively

Typo
4th September 2005 Martin Moene, Thomas Schell, Martin Rottinger page 337

The variable a should be b in the expression boost::polymorphic_cast<Derived*>(a)

Typo
4th September 2005 Martin Moene page 331

The variable p should be py in the expression func(interface_cast_noaddref<IX>(p))

Typo
6th January 2006 Robert Dexter page 165; listing 11.7

The GetInstance() method must be defined static.

Typo
6th January 2006 Robert Dexter page 164; listing 11.6

The GetInstance() method must be defined static.

Typo
6th January 2006 Robert Dexter page 163; listing 11.5

The GetInstance() method must be defined static.

Typo
17th August 2005 Martin Moene page 161

"Without the static, the linker would complain ..." should read "Were it not declared within an anoymous namespace, the linker would complain ..."

Typo
17th August 2005 Martin Moene page 159

"Stipulating the object files for object1.cpp, object2.cpp and object3.cpp ... ..." should read "Stipulating the object files for main.cpp, object2.cpp and object3.cpp...".

Typo
17th August 2005 Martin Moene page 139; section 10.3

"Before we and move on ..." should read "Before we move on ...".

Typo
12th August 2005 Martin Boucher, Paul Floyd page 352

There are two scope2 variables. The second one should be scope3

Typo
11th August 2005 Martin Moene page 124; listing 9.1



  printf("%s => %s", path, find_filename(fileName));

should read:

  printf("%s => %s", fileName, ffn(fileName));

Typo
8th August 2005 Martin Moene page 52; listing 3.9

The MIL of mem_buffer written as:

  mem_buffer(size_t size)
    : m_size(cb)
    , m_buffer(. . .)

should read:

  mem_buffer(size_t size)
    : m_size(size)
    , m_buffer(. . .)

Typo
11th January 2006 Robert Dexter page 196; listing 13.2

The variable i8 should be named si8. The variable ui64 should be declared as of type uint64_t.

Typo
15th March 2006 Jonny Rodin page 268; section 16.7.1

The comments for contexts 2 and 3 in the code should be the opposite way round.

Typo
29th June 2005 Martin Boucher page 441; listing 28.1

unused_return_value_monitor constructor should not be explicit, otherwise the code in listing 28.2 (page 442) will not compile. (The reason this crept in is that I condensed the actual separate one parameter and two parameter constructors in the STLSoft class into two for the book listing, and instinctively added the explicit. There's something to be said for compiling one's writing ...

Typo
28th June 2005 Juan Antonio Zaratiegui Vallecillo page 348; footnote 7

The reference to section 10.11 in fact refers to section 20.11

Typo
28th June 2005 Martin Boucher page 380; listing 22.4

class RefCounter also derives publicly from S, as well as from T (as shown in the code snipet from the beginning of section 22.4)

Typo
28th June 2005 Martin Boucher page 380; listing 22.4

The ParentClass token in the member initialiser list for the second constructor should be T.

Typo
28th December 2006 Thomas Schell page 8; section 1.2.4

The definition of must_be_pod is missing the preceeding template <typename T>

Typo
26th May 2005 Mark Hoebeke page 19; section 1.4

There are two ? tokens, when there should only be one:

  # define assert(x) ((!x) ?

    ? assert_function(#x,__FILE__,__LINE__)

    : ((void)0))

Typo
10th May 2005 Martin Boucher page 344-345; section 20.2,

The declaration
  Resource *m_vs;
Should read:
  VisualSystem *m_vs;

Typo
7th May 2005 Martin Boucher, Martin Moene page 338; listing 19.20

In the 3rd ctor of ptr_cast, the member initialisation has two typos:

  ptr_cast(pointer_type pt)
    : m_p(t)

should be

  ptr_cast(pointer pt)
    : m_p(pt)

Typo
1st January 2007 Thomas Schell page 95; section 3.4.1

the phrase

"... mystuff_gcc.a (mystuff_a.lib for Win32) ..."

should read

"... mystuff_gcc.a (mystuff_gcc.lib for Win32) ..."

Typo
30th April 2005 Martin Boucher page 77; listing 6.5

Types of m_var and m_revert were defined in terms of V, when they should be in terms of T.

  template< typename T >
  class ValueScope
  {
    ...

  private:
    T &m_var;
    T m_revert;
  };

Typo
21st April 2005 Pablo Aguilar page 45; listing 3.4

The statement
  return OnParseSymbol();
should read
  return cw.OnParseSymbol();

Typo
21st April 2005 Pablo Aguilar page 21; section 1.4.2

Instead of:
  "... experience a memory system during debugging ..."
it should read:
  "... experience a memory exception during debugging ..."

Typo
12th April 2005 Michael Toksvig, James Mansion page 422; chapter 26

"Anytime in this chapter that I refer to operator &() it will be the unary form, which is the address of operator. The binary form, which is the bitwise OR operator, is an entirely different beast."

Should read:

"Anytime in this chapter that I refer to operator &() it will be the unary form, which is the address of operator. The binary form, which is the bitwise AND operator, is an entirely different beast."

Typo
1st January 2007 Thomas Schell, Sergey Racheyev page 47; section 3.4.1

The statement
  int *&device = dc.m_device;
Should read:
  int &device = dc.m_device;

Typo
11th April 2005 Serge Krynine page 47; section 3.4.1

The statement
  int *&device = dc.m_file;
Should read:
  int *&device = dc.m_device;

Typo
8th April 2005 Phil Hodges page 173

"rationale" should be "rational" (twice)

Typo
23rd March 2005 Serge Krynine, Martin Moene Bibliography

Instead of:
  "[Vand2003]. The Comprehensive Guide ..."
it should read:
  "[Vand2003]. The Complete Guide ..."

Typo
14th September 2005 Martin Moene page 542-4; listings 35.9, 35.10 and 35.12

the final reference to DayofWeek should be DayOfWeek

Typo
23rd March 2005 Rajanikanth Jammalamadaka page 514; section 34.3.3

Instead of:
  "Comeau, GCC, and Intel do not supported nested functions in either guise."
it should read:
  "Comeau, GCC, and Intel do not support nested functions in either guise."

Typo
23rd March 2005 Jonathan Small page 152; listing 10.8

The line:

  if(NULL==value)

should read:

  if(NULL==thing)

Typo
23rd March 2005 Matthew Wilson page 152; listing 10.8

The variable declaration:

  Tss key_func(. . .);

has a typo - it's TssKey - and also looks too much like a function declaration. It's better expressed as follows:

  TssKey key_func(closeThing, . . .);

Typo
22nd January 2007 Thomas Schell page 328; listing 19.14

the ic variable should be of type IImpC*, not IImpCpp* as shown

Typo
3rd February 2007 Thomas Schell page 430

the three instances of reinterpret_cast<ULARGE_INTEGER&) should be reinterpret_cast<ULARGE_INTEGER&>

Typo
15th February 2007 Thomas Schell page 539

the default constructor method should be named LinkedList, not Rectangle

Typo
28th February 2005 Markus Elfring page 438; 17.2.1 (page 273),

The decrement operator "--" has not been printed correctly, instead looking like the "—" character.

Typo
28th February 2005 Markus Elfring page 241; listing 15.4

The interpret() function return type is Type, and not void.

Typo
28th February 2005 Markus Elfring page 143; section 10.3.3

"... flavous of Linux ..." should be "... flavours of Linux ..."

Typo
28th February 2005 Markus Elfring page 57; section 4.3

There is a semi-colon missing from the line str2.Empty();

Typo
28th February 2005 Markus Elfring page 41; section 3.2.1

The statement
  pthread_mutex_lock(&service.unlock);
should read
  pthread_mutex_unlock(service.lock);

Typo
1st February 2005 Jon Redinger page 136; section 10.1.2

The use of the member type class_type (as described later in section 18.5.3; standing for the full type of a specialised class template, or the type of a non-template class) is premature. Each occurrence of it in this listing should instead be atomic_integer

Typo
15th February 2007 Thomas Schell page 542; listing 35.9

the statement

  return WeekDay.m_value;

should read

  return DayOfWeek.m_value;

Typo
21st February 2007 Thomas Schell page 546; listing 35.14

the expression

  &C::P##_offset

should read

  &C::P##_offset##_C

Typo
22nd March 2007 Martin Rottinger page 44; listing 3.2

the variable cchDest is declared twice

Typo
22nd March 2007 Martin Rottinger page 345; footnote 4

the author is Frederick P. Brooks

Typo
8th April 2007 Thomas Schell page 213; section 14.3

the expression

  #define dimensionof(x) sizeof(byte_array_of_same_dimension_as((x)));

should read

  #define dimensionof(x) sizeof(byte_array_of_same_dimension_as((x)))

Typo
25th May 2007 Steven Allan Tague page 475; section 32.1.2

the expression

  buffer[index] = '\0';

should read

  stack_buffer[index] = '\0';

Typo
 

Click through to Amazon.com
Valid XHTML 1.0! Imperfect C++ content copyright Addison-Wesley | Additional content copyright Synesis Software Pty Ltd and Greg Peet
Website designed by Greg Peet. Thanks Greg!