Book Review


Exceptional C++

reviewed by Marc Briand


Title:Exceptional C++ — 47 Engineering Puzzles, Programming Problems, and Solutions
Author:Herb Sutter
Publisher:Addison-Wesley, 1999
Pages:208, paperback
ISBN:0-201-61562-2
Price:$33.95

I should probably disclose a bias I have before I begin this review: I am generally leery of books or articles that offer up programming puzzles. Puzzles tend to bring out the worst in authors, typically a thinly veiled smugness at having inside information, of knowing something readers don't. Having such an attitude toward readers is not conducive toward giving them real instruction.

I make an exception to my bias with Herb Sutter's new book, Exceptional C++. I find none of the typical arrogance here that characterizes the makers of puzzles. More importantly, Sutter does not stop at solving his own puzzles, but demonstrates why they're relevant to everyday programming. They are not just conjured up to showcase some obscure feature of C++.

This book has its origins in Sutter's popular Guru of the Week feature, which is posted on a regular basis to the comp.lang.c++.moderated newsgroup. Although the book does draw on past newsgroup postings, Sutter assure us it is not "just a cut-and-paste of stale GotW issues that are already floating around out there in cyberspace." He has considerably reworked the material and added much to it that is new. Even so, the book retains something of the rambling, repetitive flavor of a newsgroup. This can be annoying at times, but it does not seriously impede comprehension of the material.

Perhaps another artifact of its newsgroup origins is this book's division into "items," not chapters. We have seen the item approach before, most notably in the very successful Effective C++ books by Scott Meyers. Items are an understandably popular format in programming books. They are less threatening to readers who feel they don't have time to read an entire chapter, a condition that describes many a programmer. Although I don't want to get into a detailed comparison of the books by Meyers and Sutter, but I feel I should point out that Sutter's items are, as a rule, the less "encapsulated" of the two books. Sutter's items tend to be sequentially linked. In fact, one of the biggest sections of Sutter's book is what he calls a "miniseries" on exception-safe code. So we might say that Exceptional C++ contains a few chapters after all — they're just not called that.

But enough fussing over structure for now. What is to be found in the items? Well, a lot of interesting stuff. Sutter's typical approach is to start with a short snippet of code, and then to say, in effect, "what's wrong with this?" Be forewarned: if you tackle this book you had better enjoy reading through code — and some programmers simply do not. What is wrong with the code tends to be subtle, at least if you're at my level of expertise, which I fancy is just about average. If all Sutter did was point out, "ha ha, you didn't know that little factoid, did ya?" this would be a very annoying book indeed. Fortunately, he does not use these puzzles as ends in themselves, but to engage you in the very worthwhile discussion that follows.

Some of the subtle issues discussed involve — guess what — name lookup. This is, frankly, an area of C++ that often makes me want to take up Java. I have always found the lookup rules complicated and nonintuitive, and I can never seem to remember them once and for all. So if Sutter starting saying "ha ha" at this point I would just throw this book against the wall. Instead, he goes into great detail to explain the rationale behind the lookup rules. And behold, for the twinkling of an eye, I understand. It is a measure of Sutter's explanatory skill that my copy of his book is still in one piece.

I would be misleading readers if I gave the impression this book was all puzzles. Many of the items are presented as honest-to-God problems, such as how to minimize compile-time dependencies. I also don't want to imply that this book is just an amorphous stew of random items. There are a couple of strong themes in Sutter's writing. One is his continual emphasis on exception safety. In this book we learn that exception safety involves a couple of requirements: 1) If a function does not handle an exception, it should allow it to propagate up to a caller that can handle it (with the caveat that destructors should always handle exceptions — they should never allow an exception to escape); 2) The code should be written in such a way that resources are correctly freed and data is left in a consistent state even in the presence of exceptions.

A sad truth about C++ is that some of the features that were added to it to make life simpler for programmers brought their own unanticipated complexities. Exceptions are one such feature. Some C++ programmers still use return codes to signal exceptional error conditions, reasoning that "exceptions just make things too complicated." Whether or not this reasoning has any merit, it does have a common side effect: programmers who don't use exceptions usually don't expect to handle them either. If you are one of these programmers, you may find this book a little disconcerting, even heavy handed. Sutter says:

"Exception-unsafe" and "poor design" go hand in hand. If a piece of code cannot be made exception-safe, that almost always is a signal of its poor design.

Those are strong words, and they challenged me to look at my own code to see how it measures up. I'll spare you the ugly details. Suffice it to say I have a way to go before I'd be kosher in Sutter's book.

Another theme of Sutter's is an emphasis on proper use of inheritance. Most of us in the C++ world have had years of exposure to OO. We have finally come to understand that some things that look like they're "is-a" just "ain't-a." And yet, our libraries — even commercial ones — are riddled with bad inheritance. The most common mistake is use of public inheritance when the correct solution is containment. This mistake may seem to be relatively innocuous, and not without mitigating benefits. After all, inheritance relieves you of the chore of writing forwarding functions. But as Sutter shows, improper inheritance can have a serious impact on reuse and maintainability down the road.

The notion of design for reuse permeates this book. In dozens of little ways, Sutter encourages us to think ahead, to consider how our design decisions will affect those who use or maintain our code. Sutter's own orientation seems to be toward large-scale projects, and his book will have the most appeal to those who are creating libraries for the same. For instance, one of the items in the book deals with unnecessary inclusion of header files. Programmers who work on small projects tend to develop a careless, "the more the merrier" attitude toward headers. If they even think they might need one they include it. After all, multiple inclusion is prevented by include guards, and what's a little extra build time among friends? Large-scale programmers cannot afford such an attitude. In fact, we might define a large-scale project as one in which build time becomes a significant factor in meeting deadlines.

The Item mentioned above shows how easy it is to include unnecessary headers. Sutter presents a code snippet and then asks the reader to determine which of the included headers are really necessary to make it compile. As I had come to expect from my reading of previous items, I was surprised by the answer.

Although he does not explicitly say so, I believe Sutter would advocate programming "in the large" even if you are working on a simple one-person project. The knowledge you need to be successful in large-scale projects will make you a better programmer all around.

For such a thin little book, this one covers a lot of ground. It has a couple of unmistakable parallels with the books by Meyers. For one thing, it assumes you don't need yet another introduction to the fundamentals of C++, but for better or worse, you are already out there coding away. Somewhat like Meyers' books, this one hits on major trouble spots for C++ programmers: creation of unwanted temporaries, lack of exception safety, abuses of inheritance, unintended behaviors when using polymorphism, excessive compilation dependencies, and memory (mis)management. Sutter also throws in discussions of namespaces, interfaces, auto_ptr, and various and sundry miscellaneous topics. A lot of this is stuff that programmers should have learned back in C++ 101, but were too busy coding to pay attention.

As I hinted above, my major complaints with this book — which are really not so major — have to do with organization and flow. In places the divisions between "items" seem fairly arbitrary, and hence distracting. An item or section of a book ought to complete a thought; but in Sutter's writing, a thought is never so much put to rest as temporarily held in abeyance. Repetition is an effective tool in emphasizing concepts or principles. It is not so effective when the things being repeated are questions for the reader, such as "how well do you know memory?" or "how well do you think you understand XXX?" These chatty little questions can become irritating after a while (especially if you don't understand things as well as you thought you did).

But these flaws aren't such a big deal. They're something akin to quirky indentation in source code. You learn to read past it, and what's really important is the logic between the curly braces. There are a lot of C++ books out there. Most of them are rather unremarkable. They start off with the obligatory paean to OO, then crank through the features one-by-one. It is the rare book that takes a different approach, and the rarer one still that does so without being gimmicky. Exceptional C++ is one of those rare books. It's interesting, informative, and yes — the puzzles are even fun.

Marc Briand is Editor-in-Chief of C/C++ Users Journal. He loves programming, writing, and too many other things for his own good. However, he hates to work, which is why he is an editor. He may be reached at mbriand@mfi.com.