ACCU Home page ACCU Conference Page
Search Contact us ACCU at Flickr ACCU at GitHib ACCU at Google+ ACCU at Facebook ACCU at Linked-in ACCU at Twitter Skip Navigation

Search in Book Reviews

The ACCU passes on review copies of computer books to its members for them to review. The result is a large, high quality collection of book reviews by programmers, for programmers. Currently there are 1918 reviews in the database and more every month.
Search is a simple string search in either book title or book author. The full text search is a search of the text of the review.
    View all alphabetically
Title:
Designing Components with the C++ STL (revised Edition)
Author:
Ulrich Breymann
ISBN:
0 201 67488 2
Publisher:
Addison-Wesley
Pages:
300
Price:
£31-00
Reviewer:
Martin Fabian
Subject:
advanced c++
Appeared in:
12-4
The following extensive review is for the revised edition of a book whose 1st edition I reviewed relatively favourably. I recollect that I was not entirely happy with my review. In the context of the year 2000 I would have written something different.

I am grateful to Martin Fabian (he is not a member of ACCU) for taking time out to write and donate this review for publication.

- Francis Glassborow
The title of this book is promising. So is the (description of) the author. From the back cover:

"Dr Ulrich Breymann is Professor of Technical Computer Science and Managing Director of the Institute for Computer Science and Automation at the Hochschule, Bremen. He has nearly 20 years of experience working in industrial systems analysis and software development, and is a member of the German DIN Working Group for the standardization of C++. He has written two best- selling German books on C++, edited another and is a regular contributor of C++-related articles to numerous journals and magazines."

Unfortunately, this book does not live up to the promise. Only 50 pages into the book I was thinking of demanding my money back. Continuing reading, and trying out the downloadable examples (http://www.informatik.hs-bremen.de/~brey/stlbe.html) did not alleviate my aversion. The numerous errors, bad practice, non-standard terminology, dubious comments, non-portable (even non-compilable!) and seriously exception-unsafe code, etc. spoiled my reading.

The first half of the book explains the stl and describes its contents. The main part of this is basically a repackaging of the publicly available documentation, perhaps slightly more accessible for the beginner. The second half of the book (

Part III, Beyond the STL: components and applications) presents set operations on non-sorted containers (such as associative containers) in Chapter 6. In Chapter 7 a fast associative container is described; a hashed map implementation. For some reason overloaded operators are considered necessary (Section 7.4), '+' for union, '*' for intersection, '-' for difference and '^' for symmetric difference. (Why '<=' is not regarded as useful for expressing inclusion, I do not understand.) Chapter 8 shows a number of applications using the stl containers (why not the component developed in Chapter 7?), such as cross-referencing, indexing and a thesaurus implementation. Vectors and matrices are described in Chapter 9. For sparse matrices (Section 9.4) a comparison is made between using
std::map
and the hash-map from Chapter 7. Chapter 10 describes external sorting, both with practically no usage of internal memory and with using the available memory (again, std::containers are used). Finally, Chapter 11 shows how std::containers can be used to implement graphs, and give some basic algorithms over such graphs (Dijkstra's shortest path, and topological sorting). There is an appendix with various code snippets that the author has found useful now and then.

I lack a clear explanation of what this book really is meant to be. "Desgning components" the title says, but I do not see that much of component design. I guess the hashed associative container, and matrices and graphs qualify as components, but there is not too much depth with respect to designing them. Their implementations are merely presented, and I hardly think this is enough for a book claiming to teach/explain how todesign components using the stl. What has Chapter 8 and the Appendix to do with designing components? Chapters 7, 9, 10 and 11 are the most "nutritious" chapters, however, they only encompass a small part of the entire book, definitely too little, and definitely too little of "designing components". Is this a book for the novice or the expert? I would have to answer "neither". It contains too many errors and bad practice to be useful for the novice. The example files are not straightforwardly compilable, for instance. As for the expert, well, the book still contains too many errors and bad practice to be enjoyably reading. In addition, the presented algorithms are well-known and straightforward.

I think that std::c++ programming is beginning to come to a mature state-of-the-art, as documented, investigated and explored by people like Stroustrup, Lakos, Meyers, Sutter and others. It seems that in the latter years our knowledge about how to use what std::c++ offers has grown and matured. We, as a community, and that includes authors and publishers of c++ books, have a responsibility to teach and present examples of good coding practices and standards. This book does not contain the type of mature high-quality std::c++ code that could be expected in the year 2000.

Nonstandard terminology:

Why is the default constructor referred to as the "standard constructor"? Also, the author goes a long way in trying to make a distinction between "abstract data types" and "implicit data types". I never did understand the distinction or why it has to be made (or what an "implicit data type" is.) It has to do with what are generally known as "adaptors", a term which is briefly mentioned in the introduction to Chapter 4.

Nonportable code: :

In the second example of the book (Section 1.3.4) the author fearlessly assumes that
std::vector<int>::iterator
is equivalent to
int*
. Admittedly, a remark that this is not guaranteed is made in Section 3.1, but that is much too late.

Bad practice: :

using namespace std;
is routinely added to all header files. I understand that for the sake of brevity, it might make sense, at least in small examples in a book. Almost all books on std::c++ do this to save on space. However, most of those books also include some comment about this ("do as we say, not as we do"), as they should. Not so here. Furthermore, the downloadable files, which would represent ready-to-use "components" also include a
using namespace std;
directive, and this is truly bad. Note that even files that do not include anything from std:: have a
using namespace std;
directive at their top (for instance,
setalgo.h
, see below). Obviously these are not compilable unless some assumption about the inclusion order is made.

Plain errors: :

In the description of the containers,
const_iterator
is claimed to be returned by "container with constant elements". Of course, since constant elements are not assignable, such std::containers cannot exist, this is common knowledge. Furthermore, many of the presented functions take containers by
const
ref (as they should) but still try to get an
iterator
(as opposed to a
const_iterator
) from
begin()
. Of course, this cannot and should not compile (though it seems that MSVC++6 compiles them! Other compilers issue errors).

Dubious comments:

It is claimed that container assignment can in some cases be optimised away by the compiler inserting a swap instead. The std::c++ community has recently been discussing this question on comp.lang.std.c++.moderated, and the consensus was that the claim is dubious at best, and probably incorrect.

Inconsistent variable naming:

In some places, for no obvious reason, single letters are used for variables, in some cases single capitals. This makes for tough reading. Mostly, more reasonable naming schemes are adopted, though.

Hard-to-grasp code:

Defining two elements in a single expression, in some cases leads to unnecessarily difficult-to-read code. Especially when one of the elements is (explicitly) initialised and the other is not (see below). This problem is emphasised by extra typename keywords (and a lack of syntax colouring, of course).

Unncessary use of post-increment:

It is now well known that for iteration pre-increment usually provides better performance than post-increment. Still, the book uses post-increment throughout all the examples, thereby creating and destroying an unnecessary temporary. A good compiler may be able to optimise away that temporary, still it is not good nor common practice. In fact, in other places avoiding temporaries is explicitly a concern (Section 7.4.1, for example).

Improper use of #include:

The example code makes no difference between
#include
'ing system-headers (
#include<header>
) and #include'ing user headers (
#include "header"
). The examples only use the #include<header> directive. Of course, this requires that some compiler switch for include directories is set to point to the user directory with those files.

Seriously exception-unsafe code:

For the
HMap
(a fast associative container developed)
operator=
first removes everything from the assigned-to and then constructs a copy from the assigned-from. Obviously, if the construction of the copy throws, the resulting container is unnecessarily destroyed. This is not they way assignment is supposed to be done.

Strange advice:

Section 5.6 makes a strong argument against stl's set operations, such as
set_union
,
set_intersection
and the likes. The argument being that the output iterator passed to these algorithms "must refer to a container that already has enough space. When there is insufficient space, using an insert iterator does not always make sense." (Section 5.6.6). This argument rings hollow to me, though. If I pass an insert iterator for a non-empty container, then I am saying that I want the result of the operation appended to that container. If this is not what I want, I pass an insert iterator for an empty container. I see no problem with this.

Let us look at the initial part of setalgo.h, some of the problems noted above turn up there. The //** comments are mine.

#ifndef SETALGO_H
#define SETALGO_H
using namespace std;
//** 1) Bad practice, don't do
//** this 2) Does not make
//** sense, nothing from std
//** is included
template<class set_type>
bool Includes(const set_type&s1, const set_type&s2) {
// Is s2 contained in s1?
	if(&s1 ==&s2)
// save time if the sets are
// identical return true;
	typename set_type::iterator i2 = s2.begin(), i1;
//** 3) How readable is this?
//** 4) must be const_iterator
	while(i2 !=3D s2.end()) {
		i1 =3D s1.find(*i2++);
//** 5) unnecessary use of
//** postincrement
		if(i1 == s1.end())
// not found
		return false;
	}
	return true;
}
I also had problems with the files downloaded fromhttp://www.informatik.hs-bremen.de/~brey/stlbe.html. Opening the project workspace with MSVC++6sp3 opened an empty workspace. Trying to open the project k6.dsp, msvc++ brought up a dialog saying "This makefile was not generated by Developer Studio. Continuing will create a new Developer Studio project to wrap this makefile... Do you want to continue?" In the end, I had to create my own project files, and then files such as
setalgo.h
above were not directly compilable when included into my own files due to the spurious using namespace std;. Well, at least they get the "
int main
" right...