Known problems in using the Microsoft Visual C++ compiler, version 6.0:
Please note that Microsoft has fixed all of the problems described below
in Visual Studio.NET, so the following description is relevant only if
you are using the earlier 6.0 version.
The Microsoft Visual C++ compiler, version 6.0 (which we shall call VC++ 6.0)
fails to match the C++
standard in several ways that prevent some of the code in
Accelerated C++ from compiling properly.
This page describes the problems and shows how to change the
code to avoid the problems.
Some of these problems recur throughout the text.
For example, any problem that affects the student grading
program will occur in Chapters 4, 6, 9, and 13, because that
program occurs in all those chapters.
We describe these pervasive problems first,
followed by a list of problems specific to each chapter.
We have reported these bugs to the Microsoft folks and they
are working on fixes. For example, in the first section below,
which described persvasive problems, problem #2 has been fixed
in Service Pack 4.
In each case we offer a suggested workaround.
These workarounds generally use the #ifdef
preprocessor directive.
That directive works similarly to the #ifndef
directive that we described in §4.3/67.
The #ifdef directive asks the preprocessor to
process text up to the corresponding #endif if the
preprocessor symbol following #ifdef is defined.
The Microsoft compiler defines the symbol
_MSC_VER, which we test to conditionally include
code special to the Microsoft compiler.
Pervasive bugs:
-
When you write a using declaration for a container type, such as vector:
you should then be able to use members of that container type, particularly
type members, without further ado.
For example:
vector<double>::size_type n = 0;
Unfortunately, VC++ 6.0 complains with a message that says something like
vector<double, class std::allocator<double> > : is not a class or namespace name
The easiest way to work around this problem is to include std:: as an
explicit qualifier, even though it should not be necessary:
using std::vector;
#ifdef _MSC_VER
std::vector<double>::size_type n = 0;
#else
vector<double>::size_type n = 0;
#endif
-
VC++ 6.0 prior to Service Pack 4 does not properly handle function
arguments passed to template functions. This bug affects the student
grading program that appears in a number of places in
Accelerated C++. The problem occurs when using
compare as an argument to the standard-library sort function:
sort(vs.begin(), vs.end(), compare);
One workaround is to define the < operator for
Student_info, which sort can use automatically.
First define the appropriate function:
#ifdef _MSC_VER
bool operator<(const Student_info& x, const Student_info& y)
{
return x.name() < y.name();
}
#endif
Then replace the relevant calls as follows:
#ifdef _MSC_VER
sort(vs.begin(), vs.end());
#else
sort(vs.begin(), vs.end(), compare);
#endif
A simpler workaround, but one that uses language features that do not
appear until Chapter 10, is to place an explicit & operator before
compare:
#ifdef _MSC_VER
sort(vs.begin(), vs.end(), &compare);
#else
sort(vs.begin(), vs.end(), compare);
#endif
We believe that this bug was fixed in Service Pack 4.
-
The MS library fails to properly pad string output. Thus calls, such as
cout << setw(maxlen+1) << students[i].name;
should pad the output so that whatever value is in students[i].name
is padded out to use at least maxlen+1 characters.
Instead, the library provides no padding and so the names run into the next output.
When we wrote the book, we assumed that fixing this problem would make our
programs correct.
Unfortunately, because of our inability to test the code, we failed to realize
that setw would pad on the left rather than on the right,
which is not the behavior we wanted.
The easiest way to work around both of these problems is to write the required padding
explicitly. For example:
#ifdef _MSC_VER
cout << students[i].name;
cout << string(maxlen - students[i].name.size() + 1, ' ');
#else
cout << setw(maxlen+1) << students[i].name;
#endif
We have adopted this approach in the second and subsequent printings of
Accelerated C++.
-
The MS library does not define the min and max
algorithms, which should be found in <algorithm> The
workaround we use is to define a new header file, say
minmax.h, which we include in any file that uses these
functions:
#ifndef GUARD_minmax_H
#define GUARD_minmax_H
#ifdef _MSC_VER
// needed to cope with bug in MS library:
// it fails to define min/max
template <class T> inline T max(const T& a, const T& b)
{
}
template <class T> inline T min(const T& a, const T& b)
{
}
#endif
#endif
Notes about specific chapters (including localized bugs):
Chapters 0-2
The code in these chapters should compile without complaint.
Chapter 3
Programs in this chapter will require workarounds for the pervasive bugs
described above. In particular, the definition of vec_sz
near the top of page 47 needs to be changed from
typedef vector<double>::size_type vec_sz;
to
typedef std::vector<double>::size_type vec_sz;
Chapters 4-5
Programs in these chapters will require workarounds for the
pervasive bugs described above.
Chapter 6
Programs in this chapter will require workarounds for the
pervasive bugs described above.
In additon, although the program to find URLs should have
using declarations for the character classification
functions, isalpha and isalnum, VC++ 6.0 mistakenly
says that these functions are not part of the std namespace.
You can work around this bug by omitting the using
declarations:
#ifndef _MSC_VER
using std::isalpha;
using std::isalnum;
#endif
Chapter 7
Programs in this chapter will have to work around the first
pervasive bug described above.
Chapter 8
- Problem #1 from above applies also to generic uses of
containers and requires a similar workaround.
For example, in the generic median program, it should be legal to write:
using std::vector;
typedef typename vector<T>::size_type vec_sz;
But for VC++ 6.0, we must instead write:
typedef typename std::vector<T>::size_type vec_sz;
- In the split function, it is correct to include a
using declaration for the std::isspace function, but
as in Chapter 6 and the isalpha and isalnum
functions, VC++ 6.0 incorrectly says that isspace is
not in namespace std. Use the same workaround--do not
include a using declaration for isspace.
Chapter 9
Programs in this chapter will require workarounds for the
pervasive bugs described above.
Chapter 10
The code in this chapters should compile without complaint.
Chapter 11
The allocate member of class std::allocator is defined to
take a single argument of type size_t.
VC++ 6.0 incorrectly requires a second argument, which it uses as a hint
to optimize the performance of allocate.
A null pointer can be passed as the second argument,
which has the effect of not offering a hint.
To work around the problem, rewrite each of the calls to allocate to pass this extra,
non-standard argument.
For example, we can rewrite the call to allocate in Vec::create as follows:
#ifdef _MSC_VER
data = alloc.allocate(n, 0);
#else
data = alloc.allocate(n);
#endif
Chapter 12
Similar to the problems in Chapters 6 and 8, where VC++ 6.0
fails to include the character classification functions
(isalpha, isalnum, isspace etc.)
as part of the std namespace, it also fails to
include the strlen function in std.
The workaround is analogous: Omit the qualification of std::strlen.
For example, in the Str constructor that takes a const char*:
#ifdef _MSC_VER
std::copy(cp, cp + strlen(cp), std::back_inserter(data));
#else
std::copy(cp, cp + std::strlen(cp), std::back_inserter(data));
#endif
Chapter 13
Programs in this chapter will require workarounds for the
pervasive bugs described above.
In addition, the return type for the clone function
in class Grad must be changed to be a Core* rather than a Grad* as written in the book:
#ifdef _MSC_VER
Core* clone() const { return new Grad(*this); }
#else
Grad* clone() const { return new Grad(*this); }
#endif
because VC++ 6.0 does not yet allow a virtual function returning a
pointer (or reference) to a base class to be defined in a derived
class to return a pointer (or reference) to the derived type.
Chapter 14
The programs that reimplement earlier programs using Handle or Ptr
will have to be fixed as described in the related chapter.
For example, the student grading solution that uses a vector< Handle<Core> >
will have to be corrected for the pervasive problems described above.
Similarly, the Str class that is reimplemented using a Ptr
will need to be adjusted to account for the MS bug related to strlen described in Chapter 12.
Chapter 15
Various functions use the max algorithm from the library
and so, as described above, the calls to max will have to be
replaced by corresponding calls to your own version.
For example, in VCat_Pic:
class VCat_Pic: public Pic_base
{
wd_sz width() const
{
return std::max(top->width(), bottom->width());
}
could be rewritten as:
class VCat_Pic: public Pic_base
{
#ifndef _MSC_VER
return std::max(top->width(), bottom->width());
#else
return max(top->width(), bottom->width());
}
Of course, a declaration for your version of max
would also have to be included in the file in which this code resides.
Chapter 16
Programs in this chapter will require workarounds for the
pervasive bugs described above.