Published on Linux DevCenter (http://www.linuxdevcenter.com/)
Everyone knows that memory management is a difficult and dangerous chore in C++. This series of three articles will show you that the conventional wisdom is not true. When approached correctly, C++’s seemingly archaic memory-management scheme actually provides an opportunity to create spectacular programs ? programs that would not be possible with more modern languages that handle memory automatically.
This article, part one in a series, discusses C++ in the context of several other popular languages. It also describes the kinds of memory errors that can occur in C++ programs. The most common specific errors are then presented in a set of tables, for easy reference when developing your own code.
Subsequent articles in the series will demonstrate a different way of thinking about memory management ? not as a dreaded danger to be faced with stoic resolve, but as a powerful and subtle tool for improving your work. In many situations, the C++ approach to memory resources is not cause to avoid the language, but actually the reason why it should be used!
Choosing the Right Language: C++ and Some Alternatives
Not so long ago, C and C++ were about the only practical choices for serious software development on microcomputers. This is no longer the case. Java, Python, and Perl are three established, mainstream alternatives that can be used for many applications today. These new languages run on multiple platforms, feature extremely rich libraries for everything from encryption to graphics, and are supported by large, enthusiastic user communities. They are freely available (although Java’s source code is not open like the other two). All three are widely used in business, government, and research.
In contrast to C and C++, the newer languages (Java, Python, and Perl) have automated memory management. This ranges from Python’s simple reference-counted model to Java’s sophisticated garbage collector. To the programmer, however, the final result is nearly always the same: no more worrying about memory errors. Why, then, even bother considering C or C++? Why not just choose one of the memory-managed languages and live happily ever after?
Sometimes, a Memory-Managed Language is Really the Best
In many applications, a memory-managed language is indeed the right choice. Scripts to automate a small to medium-sized web site, for example, are best written in Perl or Python. To analyze your server’s logfile, Perl is probably the best choice. A single-user application with an excellent GUI can be built in Java. Complex object-oriented programs are quickly and easily written in Python.
Even older systems written in C or C++ can benefit from the addition of new code in one of the memory-managed languages; Java, Python, and Perl all provide features that make such integration possible. Do C and C++, which require low-level operations to handle memory, have any significant role left to play in modern software development? The answer is yes, as the following discussion will show.
When a Low-Level Tool is Better
Languages that give you precise control over system resources remain highly relevant to this day ? and not only for embedded systems or kernel-level code. If your project is a user-space server or must perform lots of computation (e.g., a graphics package or a game), you will save yourself a great deal of trouble by avoiding the memory-managed languages, at least for the core of your system.
As described previously, many situations are handled by the automated, general-purpose allocation strategies of the memory-managed languages. In many other cases, however, resource management becomes critical. Making efficient use of a server’s RAM, for example, is a daunting task with a memory-managed language. Your control is minimal, so precisely matching data structures to algorithms is a highly uncertain process.
It is possible to learn how to use a language such as C++ correctly. On the other hand, trying to get Java’s garbage collector (just to pick one example) to take a specific action at a certain time is an impossible task. Sometimes it will work, then break with no explanation. The behavior will depend on which JVM you are using, so your code will not be portable. Even on the same platform, JVM upgrades will unleash mystifying, subtle errors. This is precisely the kind of nightmare that is typically associated with memory allocation errors in C++!
Because memory-managed languages seem so automatic at first glance, many programmers assume that their greatest worries are over once they choose such a language. Hopefully, their luck will hold up, and they can live a happy life. For the multitude that will not be so fortunate, there is a hard and painful lesson waiting here: errors in memory management almost always lead to disaster. A memory-managed language does not change that; it gives you a generic (albeit well-designed) strategy to deal with the problem. If, however, the generic strategy is wrong for your project, then you will have made a memory management error, and you will pay for this error just as surely as if you had coded it yourself.