The Assembly Language of Object-Oriented Programming 205 A low-level language demands attention to myriad details, most of which have more to do with the machine’s internal operation than with the prob- lem being solved. Not only does this make the code inscrutible, but it builds in obsolescence. As new systems come along, practically every other year these days, low-level code becomes out of date and must be manually patched or converted at enormous expense. Pardon Me, Your Memory Is Leaking… High-level languages offer built-in solutions to commonly encountered problems. For example, it’s well known that the vast majority of program errors have to do with memory mismanagement. Before you can use an object, you have to allocate some space for it, initialize it properly, keep track of it somehow, and dispose of it properly. Of course, each of these tasks is extraordinarily tedious and error-prone, with disastrous conse- quences for the slightest error. Detecting and correcting these mistakes are notoriously difficult, because they are often sensitive to subtle differences in configuration and usage patterns for different users. Use a pointer to a structure (but forget to allocate memory for it), and your program will crash. Use an improperly initialized structure, and it corrupts your program, and it will crash, but perhaps not right away. Fail to keep track of an object, and you might deallocate its space while it’s still in use. Crash city. Better allocate some more structures to keep track of the struc- tures that you need to allocate space for. But if you’re conservative, and never reclaim an object unless you’re absolutely sure it’s no longer in use, watch out. Pretty soon you’ll fill up with unreclaimed objects, run out of memory, and crash. This is the dreaded “memory leak.” What happens when your memory space becomes fragmented? The rem- edy would normally be to tidy things up by moving the objects around, but you can’t in C++—if you forget to update every reference to every object correctly, you corrupt your program and you crash. Most real high-level languages give you a solution for this—it’s called a garbage collector. It tracks all your objects for you, recycles them when they’re done, and never makes a mistake. When you use a language with a built-in garbage collector, several wonderful things happen: • The vast majority of your bugs immediately disappear. Now, isn’t that nice? • Your code becomes much smaller and easier to write and under- stand, because it isn’t cluttered with memory-management details.
206 C++ • Your code is more likely to run at maximum efficiency on many dif- ferent platforms in many different configurations. C++ users, alas, are forced to pick up their garbage manually. Many have been brainwashed into thinking that somehow this is more efficient than using something written by experts especially for the platform they use. These same people probably prefer to create disk files by asking for platter, track, and sector numbers instead of by name. It may be more efficient once or twice on a given configuration, but you sure wouldn’t want to use a word processor this way. You don’t even have to take our word for it. Go read The Measured Cost of Conservative Garbage Collection by B. Zorn (Technical Report CU-CS- 573-92, University of Colorado at Boulder) which describes the results of a study comparing performance of programmer-optimized memory manage- ment techniques in C versus using a standard garbage collector. C pro- grammers get significantly worse performance by rolling their own. OK, suppose you’re one of those enlightened C++ programmers who wants a garbage collector. You’re not alone, lots of people agree it’s a good idea, and they try to build one. Oh my, guess what. It turns out that you can’t add garbage collection to C++ and get anything nearly as good as a language that comes with one built-in. For one thing, (surprise!) the objects in C++ are no longer objects when your code is compiled and running. They’re just part of a continuous hexadecimal sludge. There’s no dynamic type infor- mation—no way any garbage collector (or for that matter, a user with a debugger) can point to any random memory location and tell for sure what object is there, what its type is, and whether someone’s using it at the moment. The second thing is that even if you could write a garbage collector that only detected objects some of the time, you’d still be screwed if you tried to reuse code from anyone else who didn’t use your particular system. And since there’s no standard garbage collector for C++, this will most assur- edly happen. Let’s say I write a database with my garbage collector, and you write a window system with yours. When you close one of your win- dows containing one of my database records, your window wouldn’t know how to notify my record that it was no longer being referenced. These objects would just hang around until all available space was filled up—a memory leak, all over again.