views:

260

answers:

3

Let's say I have an object Employee_Storage that contains a database connection data member. Should this data member be stored as a pointer or as a reference?

  • If I store it as a reference, I don't have to do any NULL checking. (Just how important is NULL checking anyway?)

  • If I store it as a pointer, it's easier to setup Employee_Storage (or MockEmployee_Storage) for the purposes of testing.

Generally, I've been in the habit of always storing my data members as references. However, this makes my mock objects difficult to set up, because instead of being able to pass in NULLs (presumably inside a default constructor) I now must pass in true/mock objects.

Is there a good rule of thumb to follow, specifically with an eye towards testability?

+5  A: 

It is almost never prefereable to store references as data members, and a lot of the time it is impossible. If the objects must be assignable (as they must to be stored in a standard library container), references cannot be used. Also, references cannot be reseated, so once a reference is initialised with an object, it cannot be made to refer to a different object.

See this question http://stackoverflow.com/questions/892133/should-i-prefer-pointers-or-references-in-member-data for a more detailed discussion of the issue.

anon
+3  A: 

It's only preferable to store references as data members if they're being assigned at construction, and there is truly no reason to ever change them. Since references cannot be reassigned, they are very limited.

In general, I typically store as pointers (or some form of templated smart pointer). This is much more flexible - both for testing (as you mentioned) but also just in terms of normal usage.

Reed Copsey
Regarding your point about only using references when there is no reason to ever change them - Couldn't I accomplish the same thing with pointers by using a const pointer? (Object * const m_ptr <-- This pointer can't be changed.) If so, then it seems like there's even less of a reason to use references...
Runcible
@Runcible: True, although the usage of references is a bit "nicer" than the usage of pointer members, so if you really want that behavior, references are often cleaner to work with. I very rarely use references for members, though - it's just too inflexible in most cases.
Reed Copsey
I see. And what about NULL checking? Given that you're using pointer members, do you have to do NULL checking all over the place? I've been told that too much NULL checking just amounts to paranoid programming and additional code bloat. I'm curious what your approach is.
Runcible
It depends - when I'm using exceptions, I try to wrap my assignment and put the NULL checking into the assignment function, but not necessarily in usage. This gives you the best of both worlds - all of the checking at assignment time, but none of the need for it as you use it, since it's guaranteed to be assigned (or you threw before).
Reed Copsey
Hippiehunter
Runcible
@Reed Copsey: Thanks for the insight! Just to add on to this, I found an article by Misko Hevery about NULL checking: http://misko.hevery.com/2009/02/09/to-assert-or-not-to-assert/
Runcible
+1  A: 

Given a choice, I like to use the most constrained type possible. So if I don't need to support null objects I'd much prefer to declare a

Foo& m_foo;

member rather than a

Foo*const m_foo;

member, because the former declaration documents the fact that m_foo can't be null. In the short term, the advantage isn't that great. But in the long run, when you come back to old code, the instant assurance that you don't have to worry about the case of m_foo being null is quite valuable.

There are other ways of achieving a similar effect. One project I worked on where they didn't understand references would insist any potentially null pointers be suffixed '00' e.g m_foo00. Interestingly, boost::optional seems to support references although I haven't tried it. Or you can litter your code with assertions.

timday