Good code is a beautiful thing--especially when you don't have to write it. While most of us are quick to use prepackaged containers such as vectors, lists, and maps in everyday programming, we often overlook algorithms as a reuse tool. Find out how standard template library algorithms, specifically, can put you on the road to reuse.
If you're like me, you like good code-like to read it and, especially, like to write it. So, what is good code? Code that has no redundancy? Code that has small functions? If time and management allow, we all should refactor our code so it has the nice properties experts tell us about.
But for me, the best code of all is code that I don't have to write.
Reuse has been a software Holy Grail for some time, and it finally seems to be paying off. Python, for example, has hundreds of packages in its standard library, and Java comes with thousands of useful classes. Using libraries should be automatic for programmers.
In this article I discuss what I believe is the most underused library in the C++ world-one that Java developers could take advantage of, too.
Most of us are quick to use prepackaged containers such as vectors, lists, and maps in everyday programming. Where I see considerably less reuse is with algorithms. Algorithms-only the very essence of computer science! Go figure.
Quick quiz:Howmany common, general-purpose algorithms, like quicksort or binary search , can you think of? How many should a generic algorithms library provide?
Let me pose a similar question: How many distinct standard template library (STL) algorithms are there in the standard C++ library? If you're a C++ developer, you've probably used sort, find, count, and maybe even for_each and transform. How many are there altogether?
More than seventy!
The power of the STL algorithms derives from several factors:
- They are templates, so they accommodate any type of argument with static type checking.
- They work with built-in arrays as well as with sequence containers such as vector, list, deque, or any container of your own making that fills certain reasonable requirements.
- They work with built-in types without any boxing/unboxing overhead.
- Many of the algorithms accept functions or function-like objects as parameters, allowing you to customize their behavior.
- Many useful function objects are available out of the box and can be combined with adaptors, also provided, so that you may discard many of the loops or functions that you might be writing today, saving you time and debugging headaches.
The result is an incredibly robust toolset. What follows are some examples that I hope you'll find interesting and useful.
To obtain the smallest element in an array of N elements, just call:
All input sequences are delimited by a "pointer" to the beginning (myarray) and one past the end (myarray+N). Pointer is quoted in the previous sentence because you can also repeat the request for sequences other than arrays by using their iterators:
The begin() and end() functions in the standard C++ containers return iterator objects that behave like pointers.
How many zeroes are there in a sequence? Try:
count(myvector.begin(), myvector.end(), 0)
How many positive elements are there? You could pass a greater-than-zero function to the count_if algorithm, as shown in listing 1.
All count_if needs is something that can be called as a single-argument function for every element in the given sequence.
You might find it easier, though, to use the built-in greater function object. A function object is just a class that implements the function call operator (operator()). The greater function object is a binary function, of course, so it needs to be adapted to work as a unary function with count_if. Here's how to make that happen:
The bind2nd adaptor function takes something that is callable as a binary function and wraps