Advice From the C++ Experts: Write What You Know, and Know What You Write
This article appeared in C++ Report, 9(9), October 1997.
My best advice? Don't get fancy. Treat a new C++ feature like you would treat a loaded automatic weapon in a crowded room: never use it just because it looks nifty. Wait until you understand the consequences, don't get cute, write what you know, and know what you write.
Cuteness does hurt, for at least two reasons. First, cute code hurts portability. The cute programming trick you used to good effect under one compiler may not work at all on another. Worse, the second compiler might accept the code but produce unintended results. For a simple example, many compilers don't support default template arguments or template specialization, so any code that relies on those features is effectively nonportable today. For a subtler example, many compilers disagree on how to handle multiple active exceptions -- and if you just did a double-take, thinking that multiple active exceptions aren't allowed (a popular misconception), just imagine how the poor compiler manufacturers must lose sleep over it since there can indeed be any number of simultaneously active exceptions during stack unwinding.
Second, cute code hurts maintainability. Always remember that someone will have to maintain what you write. What you consider a neat programming trick today will be cursed as an incomprehensible rat's nest tomorrow by the person maintaining your code... and that maintainer might be you. For example, a certain graphics library once made "cute" use of what was then a new language feature: operator overloading. Using this library, your client code to add a control widget to an existing window would look something like this:
Instead of being cute, the library writers should have followed Scott Meyers' excellent advice to "do as the ints do." That is, when using operator overloading or any other language feature for your own classes, when in doubt always make your class follow the same semantics as the builtin and standard library types.
Write What You Know, and Know What You Write
When writing code, "write what you know." Consciously restrict yourself to the language features you understand well enough to write them correctly in your sleep. (You do dream about C++ code, don't you?) For those newer to C++, this probably means using it as just a better C, and there's absolutely nothing wrong with that.
Next, "know what you write." Be aware of the consequences of what your code actually does. Among other things, keep up your reading in magazines like this one; you'll need that continuous self-improvement to stay current with and deepen your understanding of your chosen programming language. For example, the following dangerous idiom crops regularly every few months on the C++ newsgroups:
These people mean well: the intent is to improve consistency by implementing copy assignment in terms of copy construction, using explicit destruction followed by placement new. On the surface, this has the benefit of avoiding writing similar code in two places which would then have to be maintained separately and could get out of sync over time. This code even works in many cases.
But do these programmers really "know what they write"? Probably not, since there are subtle pitfalls here, some of them quite serious. Here are just four: 1. This code slices objects whenever *this and other are not the same type. 2. Consider how its correctness could depend on whether operator=() was declared virtual in a base class or not. 3. It's almost always less efficient because construction involves more work than assignment. 4. It makes life a living hell for the authors of derived classes. I'm sometimes tempted to post the above code in the office kitchen with the caption: "Here be dragons."
Is there anything wrong with the original goal of improving consistency? No, but in this case "knowing what you write" would lead the programmer to achieve consistency in a better way, for example by having a common private member function that does the work and is called by both copy construction and copy assignment. (Yes, I know that an example like the above actually appears in the draft standard. Pretend it's not there. That was to illustrate something different, and shouldn't encourage imitation.)
C++ is a wonderful language that I enjoy using daily. At the moment, it's my primary programming language. It has drawbacks compared to other languages I've used: for example, it has no real module system, and no standard garbage collection. It also has solid features available in few or no other languages: for example, its flexible templates support completely new styles of generic programming. Bottom line, C++ has more power than any of us can handle all at once. I doubt that there are more than half a dozen people on the planet (and I have specific names in mind here) who are true experts in the entirety of C++, from the core language to all the facets (pun intended) of the standard library. Most of the rest of us can only aspire to know a few narrow areas in depth and the whole reasonably well.
Fortunately, there's no need for us to all be Stroustrups or Koenigs to get concrete benefits from C++. Just avoid the dusty corners of the language, and remember that cuteness hurts in many ways. Above all, "write what you know, and know what you write," and you'll certainly do well!