Rein Halbersma wrote:
There are many other places where explicit loops and comparisons could be eliminated by proper usage of the <algorithm> part of the STL.
Of course the downside of this approach is that you have to use the STL.
Random example #1: STL container types are heavily templated, causing lots of generated code bloat in a large program that uses vector<> or other containers over lots of different types. I've seen large codebases that contained instantiations of vector<> for hundreds of different types, adding up to
several megabytes of generated code. On some platforms you just cannot afford this. Even on PCs with abundant RAM and virtual memory, more code still means more page faults, or at least more icache misses. To avoid this penalty, we use our own container class implementations that are compatible with <algorithm> etc. but were designed to keep generated code size to a minimum while still being reasonably efficient.
Random example #2: For a long time, the compiler for one of the current-gen consoles did not optimize well small inline functions with boolean return values (it generated 7 instructions instead of 2, or something). This is unfortunately a common pattern with STL predicates, iterator comparison operators, etc. So the recommendation on that platform is to not use iterators for performance-sensitive loops.
Personally, I don't like the STL container classes much. Iterators are overly complex and unsafe. Rules for iterator invalidation are inconsistent from container to container, the APIs are inconsistent, etc. <algorithm> does have a few useful tidbits in it. I probably use std::sort and std::lower_bound more often than anything else. The old C++ iostream stuff is a disaster and is best avoided.
...The rest of this post is my own opinionated stance about C++. Others will certainly have a different view! On this topic though, everyone who disagrees with me is WRONG!
C++ is full of dangerous features that are awfully easy to hurt your performance (or your sanity) with: exceptions, default constructors, member function pointers, and so on. The STL is like everything else in C++: it has some goodness if you use it properly (and carefully), but its awfully easy to shoot yourself in the foot with it.
One way of using C++ that is relatively safe is, to use it as "C with classes". Use inline methods to make code more readable. Turn off exceptions and RTTI. Do file I/O and string operations just like you would in C: sscanf, sprintf etc. still work just fine. (Or use std::string when you just don't care). When you need dynamic arrays, use vector<> unless you have something you know is better. Don't use any linked-list containers unless you are sure you know what you're doing. I think vector<> and map<> cover 95% of all reasonable container-class use cases for most programs.
Don't use virtual methods except where you need them. Don't use multiple inheritance except to mix in small classes with no virtual methods or alternatively, to mix in abstract base classes (what would be known as "interfaces" in a language like Java). Don't use virtual base classes. Don't use pointer-to-member types (they're useful for type deduction, and for implementing delegates, and... thats about it). Use operator overloading for math types only (e.g. vector/matrix). Make constructors explicit if they are costly and you don't want to call them by accident.
Use templates to make code safer and clearer, but DON'T use more than 1 level of templates unless you enjoy debugging pain. Container classes are a good use of templates. Computing integer square roots at compile time is a bad use of templates. Template metaprogramming is the land of undebuggability. Boost is a good example of the horrors that are possible with C++. It seems all nice when you're a user of it... until the first time you hit some difficult problem and have to debug the guts of boost in order to solve it. Save your time and sanity by just not using boost in the first place.