Sometimes I have to remind myself of things I used to know but forgot over the intervening years.
With C++ it’s two things.
First, when playing with a complex algorithm (such as the polygon manipulation algorithms I’ve been playing with, or with earlier algorithms on computational algebra), it’s important to understand the algorithm enough to properly design the data structures.
In a language such as Lisp or Java (both which have properly functioning garbage collectors), you can concentrate on the algorithm design and not worry too much about the data structure design: after all, if things just get ‘dropped’ or not handled correctly, the garbage collector will clean up after you. You can focus, in other words, on tinkering with the algorithm without worrying too much about the data structures–and adjust the data structures as you go along to match.
In a language such as C++, however, you have to worry about memory allocation. So it’s important to get the data structures right. And what that means is:
Who owns the data?
For a polygon mesh merge algorithm, the instinct is just to toss all the rings representing the mesh into an ArrayList, and call it a day. But then, ownership of the records (the edges, the half-edges, the inner rings, the points) is implicit in the references off the rings in the list.
But in C++, all of the records associated with the mesh need a single owner. (Or you could build a reference counting scheme, but that gets pretty messy pretty quick, even if you use Templates and create a smart pointer object.) So ideally your merge algorithm is passed a single unitary Object which owns all of the components (points, rings, edges, etc) in the polygon mesh, and has responsibility for managing ownership. Of course that object also manages the relationships between the different records.
The same can be said about a computational algebra system: who owns the representation of the formula being processed? Ideally there is a single object which owns everything, that you can use to track the records associated with that object.
Second, don’t be seduced by templates. After using Java for a while my poor brain thinks of templates as essentially an inline way of writing Java-like code in C++. But the C++ template system is essentially a very powerful preprocessor that rewrites C++ code so that template parameters (and parameter values) can be used to drive how the underlying C++ code is generated.
Instead, write the underlying code first, then go to templates if needed to simplify understanding of the code. And in some tricky situations (such as how one would pass a template compare operator to a class that uses a compare mechanism, guaranteeing the class type the template operates on is the class type passed to the compare mechanism), feel free to refer to the STL library for examples on how to solve those problems, rather than bang about trying to figure it out on my own. (Yes, I know; there are people at this point who will advocate learning templates right–but for me, the goal is to have functioning code, not to learn the subtleties of obscure magical invocations. And for templates I’ve found no “hook”, no conceptual model (aside from a complex rewrite language imposed on top of C++) to explain templates concisely.)
I want to use templates as a way to achieve generics declarations, but templates don’t quite work like Java generics. And I keep forgetting that, and I keep slamming up against the differences.