Professional C__ - Marc Gregoire [69]
Use Constants
Bad code is often littered with “magic numbers.” In some function, the code might be using 2.71828. Why 2.71828? What does that value mean? People with a mathematical background might find it obvious that this represents an approximation of the transcendental value e, but most people don’t know this. The language offers constants to give a symbolic name to a value that doesn’t change, such as 2.71828.
const double kApproximationForE = 2.71828;
Use References Instead of Pointers
Traditionally, C++ programmers learn C first. In C, pointers were the only pass-by-reference mechanism, and they certainly worked just fine for many years. Pointers are still required in some cases, but in many situations you can switch to references. If you learned C first, you probably think that references don’t really add any new functionality to the language. You might think that they merely introduce a new syntax for functionality that pointers could already provide.
There are several advantages to using references rather than pointers. First, references are safer than pointers because they don’t deal directly with memory addresses and cannot be nullptr. Second, references are more stylistically pleasing than pointers because they use the same syntax as stack variables, avoiding symbols such as * and &. They’re also easy to use, so you should have no problem adopting references into your style palette. Unfortunately, some programmers think that if they see an & in a function call, they know the called function is going to change the object and if they don’t see the & it must be pass-by-value. With references, they say they don’t know if the function is going to change the object unless they look at the function prototype. This is a wrong way of thinking. Passing in a pointer does not automatically mean that the object will be modified, because the parameter might be const T*. Both passing a pointer and a reference can modify the object or not depending on whether the function prototype uses const T*, T*, const T& or T&. So, you need to look at the prototype anyway to know if the function might change the object.
Another benefit of references is that they clarify ownership of memory. If you are writing a method and another programmer passes you a reference to an object, it is clear that you can read and modify the object, but you have no easy way of freeing its memory. If you are passed a pointer, this is less clear. Do you need to delete the object to clean up memory? Or will the caller do that? Your group should determine how variable passing techniques imply memory ownership. The preferred way of handling memory is to use smart pointers which are discussed in detail in Chapter 21.
Use Custom Exceptions
C++ makes it easy to ignore exceptions. Nothing about the language syntax forces you to deal with exceptions and you could easily write error-tolerant programs with traditional mechanisms such as returning nullptr or setting an error flag.
Exceptions provide a much richer mechanism for error handling, and custom exceptions allow you to tailor this mechanism to your needs. For example, a custom exception type for a web browser could include fields that specify the web page that contained the error, the network state when the error occurred, and additional context information.
Chapter 10 contains a wealth of information about exceptions in C++.
Language features exist to help the programmer. Understand and make use of features that contribute to good programming style.
FORMATTING
Many programming groups have been torn apart and friendships ruined over code-formatting arguments. In college, one of the authors got into such a heated debate with a peer over the use of spaces in an if statement that people were stopping by to make sure that everything was okay.
If your organization has standards in place for code formatting, consider yourself lucky. You may not like the standards they have in place, but at least you won’t have to argue about it. If everybody on your team is writing code their own