views:

529

answers:

12

Hi, everyone!

Provided, I want to pass a modifiable parameter to a function, what should I choose: to pass it by pointer or to pass it by reference?

  1. bool GetFoo ( Foo& whereToPlaceResult );
  2. bool GetFoo ( Foo* whereToPlaceResult );

I am asking this because I always considered it the best practice to pass parameter by reference (1), but after examining some local code database, I came to a conclusion, that the most common way is (2). Moreover, the man himself (Bjarne Stroustrup) recommends using (2). What are the [dis]advantages of (1) and (2), or is it just a matter of personal taste?

+18  A: 

I prefer a reference instead of a pointer when:

  • It can't be null
  • It can't be changed (to point to something else)
  • It mustn't be deleted (by whoever receives the pointer)

Some people say though that the difference between a reference and a const reference is too subtle for many people, and is invisible in the code which calls the method (i.e., if you read the calling code which passes a parameter by reference, you can't see whether it's a const or a non-const reference), and that therefore you should make it a pointer (to make it explicit in the calling code that you're giving away the address of your variable, and that therefore the value of your variable may be altered by the callee).

I personally prefer a reference, for the following reason:

  1. I think that a routine should know what subroutine it's calling
  2. A subroutine shouldn't assume anything about what routine it's being called from.

[1.] implies that making the mutability visible to the caller doesn't matter much, because the caller should already (by other means) understand what the subroutine does (including the fact that it will modify the parameter).

[2.] implies that if it's a pointer then the subroutine should handle the possibility of the parameter's being a null pointer, which may be extra and IMO useless code.

Furthermore, whenever I see a pointer I think, "who's going to delete this, and when?", so whenever/wherever ownership/lifetime/deletion isn't an issue I prefer to use a reference.

For what it's worth I'm in the habit of writing const-correct code: so if I declare that a method has a non-const reference parameter, the fact that it's non-const is significant. If people weren't writing const-correct code then maybe it would be harder to tell whether a parameter will be modified in a subroutine, and the argument for another mechanism (e.g. a pointer instead of a reference) would be a bit stronger.

ChrisW
Pointers passed into a method can't be changed to point somewhere else.
Lou Franco
@Lou - That's true; or at least, it *can* be changed, but that change wouldn't affect the caller (i.e. the callee would be changing the value of the callee's local copy of the pointer).
ChrisW
@Lou, the local copy of the pointer can, and sometimes does, get changed. This often trips up beginners who think that the caller's pointer is now changed too. Another reason to stay away from #2, (or at least avoid modifying pointer arguments) IMHO.
Nick Meyer
tstenner
+1  A: 

I choose #2 because it obvious at the point of call that the parameter will be changed.

GetFoo(&var) rather than GetFoo(var)

I prefer pass by reference for just const references, where I am trying to avoid a copy constructor call.

Lou Franco
A: 

I seem to recall that in c++ references where not null and pointers could be. Now I've not done c++ for a long time so my memory could be rusty.

Preet Sangha
+4  A: 

One advantage to passing by reference is that they cannot be null (unlike pointers), obviating the need to null-check every out parameter.

luke
GetFoo(*(Foo*)0); And any GetFoo(*ptr); for that matter. It doesn't depend how the parameter is accepted, but rather how it is passed. I think quoted Stroustrup (whether real or fake) makes sense — when you use pointer is is more obvious. On the other hand, I think it's better to decide on spot which way you want to go in the particular case.
Michael Krelin - hacker
Damn, formatting ate up my asterisks!;-)
Michael Krelin - hacker
+1  A: 

Pass by reference, and avoid the whole NULL pointer problem.

rikh
A: 

The difference here is relatively minor.

A reference cannot be NULL.

A nullpointer may be passed. Thus you can check if that happens and react accordingly.

I personally can't think of a real advantage of one of the two possibilities.

StampedeXV
For one, I don't consider this difference "minor" -- it's the difference between an object and no object, after all. Also, there's another difference: A pointer might easily be invalid (point to a random address), while a reference cannot easily be invalid.
sbi
A: 

I find this a matter of personal taste. I actually prefer to pass by reference because pointers give more freedom but they also tend to cause a lot of problems.

erelender
A: 

The benefit to a pointer is that you can pass nothing, ie. use it as if the parameter was completely optional and not have a variable the caller passes in.

References otherwise are safer, if you have one its guaranteed to exist and be writeable (unless const of course)

I think its a matter of preference otherwise, but I don't like mixing the two as I think it makes maintainace and readability of your code harder to do (especially as your 2 functions look the same to the caller)

gbjbaanb
+3  A: 

Advantages to passing by reference:

  • Forces user to supply a value.
  • Less error-prone: Handles pointer dereferencing itself. Don't have to check for null inside.
  • Makes the calling code look much cleaner.

Advantages to passing pointer by value:

  • Allows null to be passed for "optional" parameters. Kinda an ugly hack, but sometimes useful.
  • Forces caller to know what is being done w/ the parameter.
  • Gives the reader half a clue of what might be being done w/ the parameter without having to read the API.

Since reference passing is in the language, any non-pointer parameters might be getting modified too, and you don't know that pointer values are being changed. I've seen APIs where they are treated as constants. So pointer passing doesn't really give readers any info that they can count on. For some people that might be good enough, but for me it isn't.

Really, pointer passing is just an error-prone messy hack leftover from C which had no other way to pass values by reference. C++ has a way, so the hack is no longer needed.

T.E.D.
+3  A: 

I'd recommend that you consider (may not be best for every situation) returning Foo from the function rather than modifying a parameter. Your function prototype would look like this:

Foo GetFoo() // const (if a member function)

As you appear to be returning a success/failure flag, using an exception might be a better strategy.

Advantages:

  • You avoid all of the pointer/reference issues
  • Simplifies life for the caller. Can pass the return value to other functions without using a local variable, for example.
  • Caller cannot ignore error status if you throw an exception.
  • Return value optimization means that it may be as efficient as modifying a parameter.
Fred Larson
Exception may sometimes be a bad option for signalling an error. My last two projects were built with -no-exceptions flag, leaving the only option to signal an error by returning a value...
SadSido
@SadSido: Of course. I said, "... using an exception might be a better strategy." You said, "Exception may sometimes be a bad option...". Both statements are correct. In general, though, I believe exceptions are a better solution.
Fred Larson
A: 

These days I use const references for input parameters and pointers for out parameters. FWIIW, Google C++ Style Guide recommends the same approach (not that I always agree with their style guide - for instance they don't use exceptions, which usually does not make much sense)

Nemanja Trifunovic
A: 

My preference is a reference. First, because it rhymes. :) Also because of the issues pointed out by other answers: no need to dereference, and no possibility of a reference being NULL. Another reason, which I have not seen mentioned, is that when you see a pointer you cannot be sure whether or not it points to dynamically allocated memory, and you may be tempted to call delete on it. A reference, on the other hand, dispenses with any ambiguity regarding memory management.

Having said that, there are of course many cases when passing a pointer is preferable, or even necessary. If you know in advance that the parameter is optional, then allowing it to be NULL is very useful. Similarly, you may know in advance that the parameter is always dynamically allocated and have the memory management all worked out.

Dima