Conversations #2

Home Blog Talks Books & Articles Training & Consulting

On the
blog
RSS feed November 4: Other Concurrency Sessions at PDC
November 3
: PDC'09: Tutorial & Panel
October 26: Hoare on Testing
October 23
: Deprecating export Considered for ISO C++0x

Null References
Copyright © 2000 Jim Hyslop and Herb Sutter

 

Aboard ship, the last thing you want to feel is wind. Jeannine and I happened to be unlucky enough to be the closest to the incident; straining together, we managed to wrestle the bulky door shut and seal it, isolating the breached compartment. As we leaned against the door, breathing deeply, the klaxons stopped sounding.

"What in tarnation was that?" the watch officer's voice demanded shrilly over the comlink.

"Just a small penetration, sir," Jeannine responded. "We sealed off the compartment. All clear, no casualties."

"You sealed off the compartment? Why didn't it seal automatically? Didn't we just refit that door?"

Jeannine and I glanced at each other. "Uh, sir, it seems that the maintenance crews assumed the new locking mechanism would be fine, because it was brand new from the factory, so they didn't check it. It was fine, only they didn't take off all the packing materials and it couldn't seal by itself."

There was a pause, then: "All right, good work. There's a damage crew on the way." Then in the background, just before the comlink was broken, we heard the XO's voice say: "Mr. Johnson, have the chief of engineering see me in my cabin. Now. Tell Reilly to--"

I grinned at Jeannine. "I'd give a week's pay to hear that conversation. This reminds me of a code safety problem we had once, a long time ago..."

- - - - -

I had been on my first programming job for a couple of weeks, and I'd met the other programmers on my project. One of them was Bob. He was the antithesis of the Guru in almost every way: Bob was smug, his code was difficult for others to maintain, and he had a tendency to violate programming rules.

I was well into my first project, and Bob had been assigned to perform a code review on some stuff I'd checked in. He came by my desk, holding a latté, and leaned against the partition. "Your code is crashing with an access violation inside your helper function," he said. "You better fix it before the Space Cadet hears about it."

"The Guru really is an excellent programmer, Bob," I bristled. True, the Guru was odd, and I was still uneasy around her. Every time I talked to her, I kept thinking about updating my résumé. But Bob's attitude just rubbed me the wrong way somehow.

"Yeah, whatever," Bob waved his cup dismissively, sloshing a little. "Anyway, your helper function is using a null. Let's take a look."

"But the helper function doesn't use any pointers," I frowned. "Just a reference to an xWrapper class." I called up the code in my text editor. It was something like this:

class xWrapper
{
  /* ... */
public:
  virtual void dump() { cout << name << endl; }
};

void helper( xWrapper& w )
{
  w.dump();
  // ... do other stuff with w ...
}

Bob leaned at the monitor. "Yeah, it's crashing at that dump() statement," he said, scratching his nose.

"That's not possible."

"Sure it is, Junior." Bob was really starting to bug me. "All I do is get a brand new pointer from the factory, and dereference it when I pass it to you. If that pointer's null, 'course, you have a null reference. You should check for that."

"Uh, well," I faltered, less certain now. After all, I was just fresh out of school, and Bob had several years of experience. "I didn't think that was possible to see if a reference was null."

"All you do," Bob said, "is check the address of the reference. Like I said, you want to be safe, you should check for that..."

"No," the Guru's quiet voice startled us both. Once again, she had appeared at the right moment, and now stood behind us, an open tome in hand. "There is no need of such an abomination. The Standard teaches that it is not possible to have null references."

"But it is possible, dearie," Bob insisted. "We've just shown that. That's his problem."

I wanted to smack him. The Guru merely favored him with a chill glare. "No. You should check for that. Never dereference a null pointer. Change your code: If the pointer is null, do not call helper(). Show me the working code this afternoon. Begone, you instrument of malformed programs," she waved him away.

Bob blinked. But she was the senior programmer on the team, so he shut up and left.

"My apprentice," she continued to me alone, "one of the major reasons to use a reference instead of a pointer is to free you from the burden of having to test to see if it refers to a valid object. The only way to create a null reference would be to dereference a null pointer -- an act clearly forbidden by the Holy Standard, well inside the realm of Undefined Behavior."

"Okay, but why tell only me? Why not tell Bob?"

She shook her head sadly. "This he knows. I cannot teach him; he is drawn to Undefined Behavior. My apprentice, beware the path to Undefined Behavior. Once you start down that path, it will dominate your life forever. It will consume your time, as you try to track down and fix problems."

I considered this. "Well," I asked, "what about accidentally creating an invalid reference? Say you pass an object to a function, and the object you pass goes out of scope before the function is finished with it. How do you guard against that?"

She shook her head. "You cannot. In this respect, references and pointers are very similar. Consider this parable." The Guru quickly scribbled out some code on my whiteboard:

T* f()
{
  T t;
  return &t;  // return a dangling pointer
}

void f1( T* t )
{
  if( t )
    t->doSomething();
}

int main()
{
  T *tPtr = f();
  f1( tPtr );   // evil
}

"This f() quite clearly lives in infamy," she said, pushing a graying lock behind one ear, "as it returns a pointer to a local object that oversoon goes out of scope. Thus tPtr in main() points to an object that has been destroyed. f1() does the best it can -- it checks for a null pointer. Some platforms also provide compiler-specific functions that can test whether a pointer points to a valid region of memory. However, such functions would still not detect the case that, inside f1(), the variable t does not point to a valid T object. It is impossible for f1() to be certain that t is valid; therefore as the programmer writing f1(), you must have faith. Faith that your fellow programmers will do everything in their power to provide you with a pointer to a valid object.

"Just as you must assume that a non-null pointer is valid, you must assume that a reference is valid. You must have faith in your fellow programmers."

"Even Bob?" I asked.

She nodded with an air of sadness, then drifted quietly away down the corridor, reading her tome.

- - - - -

"Did Bob last long?" Jeannine asked.

"Longer than he should have." I stopped smiling. "Our company also built software that got used in pacemakers. You know, the devices they used to put inside people's chests. One time he checked in a piece of code that didn't verify all its preconditions, and the code got out into production. And..."

Jeannine lifted an eyebrow.

I nodded soberly. "Bob finally did get another job, in retail sales. He can be glad it happened before the programmer liability laws." Then the damage control team relieved us, and we got ready to go on watch.

It was not the last time I would speak with Jeannine about the Guru, or about more pleasant things.

Copyright © 2009 Herb Sutter