3 reasons to prefer references over pointers (C++)

I still remember what it was like, as a C programmer, to be introduced to the newfangled concept of references in C++. I thought: “This is dumb. It’s just another way to use pointers. More syntactic sugar for no good reason…”

For a long time, I thought of pointers vs. references as a stylistic choice, and I’ve run into lots of old C pros who feel the same. (The debate on this comment stream is typical.) If you’re one of them, let me see if I can explain why I now think I was wrong, and maybe convince you to use references where it makes sense. I won’t try to enumerate every reason–just hit a few highlights.

image credit: xkcd.com

1. References have clearer semantics

NULL is a perfectly valid value for a pointer, but you have to do some headstands to create a reference to NULL. Because of these headstands, and because testing a reference for NULL-ness is a bit arcane, you can assume that references are not expected to be NULL. Consider this function prototype, typical of so much “C++” code written by folks with a C mindset:

void setClient(IClient * client);

With only that line, you don’t know very much. Will client’s state change during the call? Is it valid to pass NULL? In the body of the call, will client ever point to anything other than the value it had at the top of the function?

Veteran C programmers recognize that the semantics are unclear, so they come up with doc conventions to plug the gap, and they check assumptions at the top of the function:

/**
 * @param client IN, cannot be NULL
 */
void setClient(IClient * client) {
    if (client != NULL) { //...do something

This is fine, except why depend on a comment and a programmer’s inclination to read and obey, when you can enforce your intentions at compile time, and write less code, too? Continue reading

Put Your Const Foot Forward

Here are two C++ style habits that I recommend. Neither is earth-shattering, but both have a benefit that I find useful. Both relate to the order in which constness shows up in your syntax.

1. When you write a conditional, consider putting the constant (unchangeable) value first:

if (0 == i)

… instead of:

if (i == 0)

The reason is simple. If you forget/mis-type and accidentally write a single = instead of two, making the expression into an assignment, you’ll get a compile error, instead of subtle and difficult-to-find misbehavior. (Thanks to my friend Doug for reminding me about this one not long ago.)

Ah, the joys of pointers… Image credit: xkcd.

2. With any data types that involve pointers, prefer putting the const keyword after the item that it modifies:

char const * VERSION = "2.5";

… instead of:

const char * VERSION = "2.5";

This rule is simple to follow, and it makes semantics about constness crystal clear. It lets you read data types backwards (from right to left) to get their semantics in plain English, which helps uncover careless errors. In either of the declarations of VERSION given above, the coder probably intends to create a constant, but that’s not what his code says. The semantics of the two are identical, as far as a compiler is concerned, but the first variant makes the mistake obvious. Reading right-to-left, the data type of VERSION is “pointer to const char” — so VERSION could be incremented or reassigned.

Use the right-to-left rule in reverse to solve the problem. If we want a “const pointer to const char”, then we want:

char const * const VERSION = "2.5";

That is a true string literal constant in C++. (Thanks to my friend Julie for teaching me this one.)

This might seem like nit-picky stuff, but if you ever get into const_iterator classes and STL containers, this particular habit helps you write or use templates with much greater comfort. It also helps if you have pointers to pointers and the like. (For consistency, I prefer to follow the same convention for reference variables as well. However, this is not especially important, since references are inherently immutable and therefore never bind to const.)

Action Item

Share a tip of your own, or tell me why you prefer different conventions.