Industry Standard C++

The other day I was browsing through the C++ API code of a third-party library. I was not much surprised to see stuff like

#define MAX(a, b) ( (a) >= (b) ? (a) : (b))
#define MIN(a, b) ( (a) <= (b) ? (a) : (b))

because despite the fact that std::min, std::max together with the rest of the C++ standard library is around for quite a while now, you still come across old fashioned code like above frequently. But things got worse:

#define FALSE 0
#define TRUE 1

and later:

...
bool someVariable = TRUE;

As if they learned only half the story about the bool type in C++. But there was more to come:

class ListItem
{
   ListItem* next;
   ListItem* previous;
   ...
};

class List : private ListItem
{
...
};

Yes, that’s right, the API guys created their own linked-list implementation. And a pretty weird one, too, mixing templates with void* pointers to hold the contents. Now, why on earth would you do that when you could just use std::list or std::vector? Makes you wonder about the quality of the rest of the code. Especially with C++ where there are so many little pitfalls and details which can burn you. Hey, if you have no clue about the very basics of a language, leave it alone!

Unfortunately, the above example is not exceptional in industry software. It seems that the C++ world these days is actually split into two worlds. In one, people like Andrei Alexandrescu write great books about Modern C++ design, Scott Meyers gives talks about Effective C++ and the boost guys introduce the next library using even more creative operator overloading that in the spirit library (which is pretty cool stuff, btw).

In the other world, you could easily call it industry reality, people barely know the STL, don’t use templates at all, or fall for misleading and dangerous c++ features like the throw() clause in method signatures. Or they ban certain c++ features because they are supposedly not easy to understand for the new guy on the project or are less readable in general. Take for example the Google C++ Style Guide. They don’t even allow exceptions, or the use of std::auto_ptr. Their take on the boost library is that “some of the libraries encourage … an excessively “functional” style of programming”. What exactly is bad about piece of functional programming used as the right tool in the right place? And what communicates ownership issues better than e.g. returning a heap allocated object using a std::auto_ptr?

The no-exceptions rule is also only partly understandable. Sure enough, exceptions increase code complexity in C++ more than in other languages (read Items 18 and 19 of Herb Sutter’s Exceptional C++ as an eye-opener. Or look here). But IMHO their advantages still outweigh their downsides.

With the upcoming new C++0X standard my guess is that the situation will not get any better, to put it mildly. Most likely, things like type inference with the new auto keyword will sell big because they save typing effort. Same thing with the long overdue feature of constructor delegation. But why would people who find functional programming less readable start to use lambda functions? As little known as the explicit keyword is now, how many people will know about or actually use the new “= delete” keyword, let alone “= default“? Maybe I’m a little too pessimistic here but I will certainly put a mark in my calender on the day I encounter the first concept definition in some piece of industry C++ software.

Update: Concepts have been removed from C++0X so that mark in my calender will not come any time soon…

23 thoughts on “Industry Standard C++”

  1. The problem is that developers typically are stuck in their ways, particularly when it comes to existing projects. There is little incentive to refactor existing code when new techniques become practical with boost or c++0x. I consider myself very fortunate to be working on a team that has recently embraced boost in a big way for new work, but even that took months of cajoling from a couple of us.

    For anyone reading this considering adding boost to your project – do it. Boost has saved us countless hours of effort. My advice for sneaking boost in is to start writing the little throwaway apps that every project accumulates using it – nobody will notice because they are not part of the main codebase. Then someday, someone will want to use some of that code and boost will have to come to.

    Regarding Google and exceptions, they actually give pretty good reasons why exceptions are not appropriate in their situation. Exceptions in the face of non-exception safe libraries can be a source of leaks and crashes if not handled correctly. Personally I would live with the extra responsibility because I love exceptions, but I can see why some might choose otherwise.

    1. Thank you for your comment, Andrew. I agree, you can consider yourself fortunate if you’re working in a team that actually has the incentive to use new techniques and libraries such as boost. It’s my experience, too, that people often are reluctant to change their way of programming. But especially in the case of boost it does not take very much to recognize its power to relieve some every day c++ pain. boost::assign is only one of many good examples.

      For the guys from my example with the self-written list class, boost would be like the 100th step. The first would be to know just the mere basics of the language they’re programming in.

    2. Boost doesn’t “have to come too” — I recently spoke with someone who was doing a reasonably good consulting business removing Boost from C++ codebases, presumably as a result of people doing very much this sort of thing. (And, to clarify, this wasn’t something he tried to sell to his customers or even personally considered a good thing; it was something they asked him to do as part of other consulting.)

      Scary, no?

  2. I do all the “good” things you say (use STL, use boost, try to write code as cleanly as I can, learn constantly), but I do use throw() in method clauses! So I’d love to know what the problem is with that. Is it that it locks down the API and makes it inflexible? Is there any efficiency gain (or loss?) from saying throw() to specify that a method doesn’t throw, or is it a waste of time?

    It might be a habit that’s a holdover from Java, but it also seems like it makes code more self-documenting… unless it has nasty side effects. 🙂

  3. Great post. I see this kind of thing all the time as well, unfortunately.

    As you said, we’re not talking about “why didn’t use partial template specialization here?” kind of stuff.

    We’re talking about “Why the hell do you have a typedef named BOOL? Why are you creating your own linked lists? Why are you explicitly assigning to member vars in your constructor instead of using the initalizer list?”

    I’m not a C++ guru, but I’ll tell you, after the stuff I see everyday, I feel like the one-eyed man in the land of the blind!!!

  4. C++ brings more pain and complexity than the “solutions” to the “problems” it was trying to solve. C is easier to understand, easier to debug, easier to maintain, produces object code that can link with other languages sanely, and is therefore, far far superior.

  5. > Now, why on earth would you do that when you could just use std::list or std::vector?

    Binary size, speed (STL implememntations differ, including basic containers and their members), compilation speed, needs for linkage with additional libraries (libsupc++ vs. libstdc++ on gcc) and so on.

    > Makes you wonder about the quality of the rest of the code.

    Using Boost/STL in the code say nothing for code quality.

    > In the other world, you could easily call it industry reality, people barely know the STL

    Utter nonsense. Sorry 🙂

    > Their take on the boost library is that “some of the libraries encourage … an excessively “functional” style of programming”

    It is clear how author of this post does not have enough understainding about functional languages to note how Google “functional” tag is made somehow ironic. C++ and Boost made facility from functional languages a joke.

  6. Re. your ListItem confusion, it’s clear you haven’t been around Real C++ Code long enough 🙂 You *can’t* always use std::list and std::vector. Think about how you would write a list data structure to disk (and reconstruct it back) in the most efficient manner possible. The answer almost always involves memory mapping a file and if upon trying to read it in the OS doesn’t give you back the same addresses, a walk of the data structure has to be done, something you can’t do with a standard container since it’s implementation can differ between compilers and platforms. Hence you roll your own. Also when STL first started to become popular, there wasn’t any standard way to control allocation (now there is) so people wishing to use their own allocators for performance reasons (e.g., faster allocations become possible and the need to walk data structures to deallocate memory can be avoided) often had no choice but to use their own data structures.

    Bonus question: what’s the best way to grow the space of std::vector? Not all implementations got it right resulting in O(N^2) complexity for appending N elements when it need never be worse than O(N log N). In such cases, again, people had to roll their own.

    Also the template/void * trick is an old way to deal with dumb linkers which could not fold together the code generated for, say, vector and vector. There’s no need to do this with Microsoft’s toolset and possibly gcc.

  7. For some reason your comment software thought template angles were HTML and mangled my previous comment. I meant to say:

    vector<int *> and vector<double *>

  8. That post exactly outlines what’s wrong with C++. It requires too much attention to detail. Why the hell can you cast an int to a bool anyway? What’s the reasoning behind that?

  9. I generally agree with your post, but while Boost and STL et al. are welcome, they are not solutions to everything. On the last big project I made with C++, the initial implementation using STL had horrible performance problems due to memory fragmentation.
    I ended up reimplementing linked lists and other basic data structures so I could manage memory allocation, dumping STL altogether.

  10. Sometimes it is absolutely necessary to invent everything yourself, to give an example. We are developing C++ on the IBM AS400. When we started with C++ in 2002, the package which contained the compiler didn’t contain stl; the compiler did not even support the bool type! Luckily in 2005/6 IBM decided to use the AIX C++ compiler on the AS400, including the STL this time and the bool type. However, because of the age of the compiler (latest version on AS400 is v7 on AIX) boost will not even compile completely. Hence, the forced construction of linked lists and macros defining TRUE and FALSE. (And we are in 2009! Argh!)

  11. Andrew, I agree with you on all that you’ve said. Especially in the finance industry, most companies are affected by the NIH syndrome.

    When interviewing candidates for a position, a few common responses that I’ve noticed primarily consisted of knowledge gaps regarding templates, premature optimization, and vehement arguments against the boost library.

    One candidate even preferred writing shared memory applications from the ground up without considering boost.shmem/boost.interprocess due to premature optimizations.

    But, one the other side, you have individuals that over-templatize, apply idiomatic anti-patterns, and over-engineer for “performance” reasons. For example, a great developer friend of mine once advised me to “not be scared to copy and paste,” which was actually incredibly surprising.

    Food for thought 😉
    Mahmoud

  12. It is quite possible that the developer wanted intrusive containers, where the user manages linked list nodes rather than the container code. This way, he/she can save on the memory allocation overhead. Just a thought….

  13. The template+void * implementation of lists avoids the code bloat that comes with using std::list. Templates are a wrapper to a small fast generic underlying implementation using void *s.

    Newbies that don’t know about this shouldn’t be in the industry.

  14. In the case of typedef BOOL (and in the specific case of the Win32 API), often it’s used because that’s what the API you’re programming to expects in its function calls, and it’s confusing to use multiple boolean types in a single program.

    Similarly, we have a lot of code at work similar to what’s described here… in particular our own implementation of a linked list, because STL isn’t available for kernel mode drivers in Windows (indeed, C++ exceptions aren’t available). We use it in our user-mode code because it assists code reuse between modules.

    C++’s story is one of “do what you have to do” and hold your nose if necessary.

  15. They’ve obviously been trying a very noble thing:
    Avoid learning as much C++ as possible.
    Use C++ classes and nothing else.

  16. I can totally understand when someone implements his own list, queue, set, or whatever. In the development of our tools we frequently realized that a user-defined implementation can improve both runtime and memory consumption. STL might be nice to prototype, but when performance is crucial, “one size fits all” does not fit anywhere.

  17. Because the language is not garbage collected, writing correct code using exceptions is far beyond the competencies of most C++ programmers.
    Worse: the result is not easily verifiable (especially if you also uses other C++ features, like operator overloading) neither automatically, nor even manually.

    Talking about using some functional constructs: why not. But NOT with C++ templates; the result is unreadable, mostly because of the stupid syntax this result in, and also because they invented their own stupid terms to do otherwise easy things in a more complicated way.

    Anyway C++ is such an evil beast that any people knowing it in depth has a different opinion of how it should be used. And that precisely for that that it should be avoided at all costs. Just use plain C for system programming or a real high level language otherwise.

  18. C++ makes me sad.

    It seems such a fractured language (as brilliantly illustrated here)– some people like boost, some hate it, some use STL, some don’t, some like full-OO, some don’t…..

    A smart guy on another blog recently commented that everybody seems to use 20% of the language– it’s just that it’s a different 20%.

    I’d love to see C++ get it’s act together and not descend into a Perl-esque quigmire, but I fear it may be too late.

    My .02,

    Rick

  19. I’m not sure you have very much experience of C++ in the wider industry judging by your comments. I maintain critical financial applications that do billions of transactions a day – across a range of hosts (Solaris, HP-UX, AIX and Linux and some more obscure embedded platforms). Let’s go through your points one by one…

    #define MIN/MAX – It’s a third party library. One of the worst things you can do with a third party library is design it so that it adds additional dependencies. If I have an app that doesn’t use the STL, I sure as hell don’t want to bother with the STL just because some other library needs to calculate min or max.

    #define TRUE/FALSE
    bool = TRUE
    Not all C++ compilers support the bool type. If you were to work on embedded systems, they often have a lot of that crap taken out.

    Writing your own linked list. Same as previous point regarding additional dependencies. Also, does the library come in binary form? If so, whose STL are you going to compile it against when you prepare a release? On Solaris I may be using the Sun standard or STLPort4. What if I take two third party libraries and find one required STLPort4 but the other requires the standard Sun STL?

    Throwing exceptions from an external library is a bad idea. On Solaris/HP-UX and Linux this has historically caused very subtle issues (where they are not caught properly) if the library is compiled with a different version on the compiler to the user code. Again, the method for throwing and catching is wrapped up with the compiler, there’s no “standard”. Remember this is in a third party library designed (presumably) to be used in many different scenarios/setups.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.