Pointers, References and Values by Michael D. Crawford Continued...

When to Use Reference Member Variables

You can store members by reference if they are guaranteed to exist elsewhere.

Reference member variables are used when the object they refer to exists outside of the scope of the class in question, and the same one is guaranteed to exist for the duration of the lifetime of your class' objects. A reference to the original is passed in as a parameter to the constructor and the reference member is initialized in the constructor's initializer list.

Reference member variables might be const or non-const. Const parameters to constructors are to be preferred when they are just used as parameters to create copies among the member variables of your class, or if you are using them to initialize a const reference member, then they'll be used in the case where the object referred to is to be accessed as const (you don't call mutating member functions, and the member functions you do call have been declared as const).

Non-const parameters to constructors are used when the member reference is itself non-const, because you want to be able to call mutating member functions on the original object.

It is a common mistake to pass a non-const reference to a constructor even when you do not intend to mutate the original. This is a mistake, as it prevents you from constructing something from an object that is itself const, and it creates unneeded headaches for maintainance programmers as they search for where an object might have been changed.

In general, you want to use a reference member variable when:

An example of a case where the lifetime guarantee applies is when the object that holds the reference member is owned by some other object, and the owner passes a reference to itself when it creates the object so they can have two-way communication.

Note that the only way to initialize a reference member is in the constructor's initializer list, as I discussed earlier. You also cannot depend on C++'s default assignment operator (simple memberwise assignment) to assign a class that does not explicitly define it. Attempting to assign a class with a reference member when no assignment operator is declared will result in a fatal compiler error.

As with auto_ptr, there are some alternatives. You could forbid assignment by declaring the assignment operator private. You could require that objects that are assigned hold references to the same object and throw an exception if they are not (you check this by comparing the addresses of the references). You could avoid assigning the reference member from the original and come up with the object it will refer to in some other way.

Most often, if you expect to assign objects with reference members, you should store the alias as a pointer rather than as a reference, so it can be changed. If you want to ensure that it always refers to an object the way a reference does, use assert() to check that the pointer is non-NULL.

There is no way to really ensure an object always exists, even with a reference. A pointer to a block that a reference exists for can still be deleted, and attempting to use the reference afterward will likely cause a crash. You can even initialize an invalid reference by dereferencing a NULL pointer:

// EvilCode.cpp

int &DoSomethingBad()
{
      int *nullPtr = NULL;

      return *nullPtr;
}

There really is no defense against intentional wickedness in C++, aside from rigourous testing - which you should do anyway, because you can always make mistakes. You can validate that the address of a reference is non-NULL in an assertion, but note that setting a reference to a NULL address is explicitly undefined in the standard so you cannot really be sure your assertion will catch this.

Code that requires references to be valid longer than the duration of a function call should be especially suspect for testing, but it can be useful.

next page previous page contents all programming tips titles

Copyright © 2000, 2001, 2002, 2005 Michael D. Crawford. All Rights Reserved.

One Must Not Trifle With Wizards For It Makes Us Soggy And Hard To Light