views:

1394

answers:

9

Let's say you have a function that modifies a variable.

Should you write it like this: void myfunc(int *a) or like this void myfunc(int &a)?

The former forces you to call the function with myfunc(&b) so the caller is aware that b will be modified, but the latter is shorter and can be called simply with myfunc(b). So which is better to use? Is there something else I'm missing?

+10  A: 

Whenever possible I use references over pointers. The reason for this is that it's a lot harder to screw up a reference than a pointer. People can always pass NULL to a pointer value but there is no such equivalent to a reference.

The only real downside is there reference parameters in C++ have a lack of call site documentation. Some people believe that makes it harder to understand code (and I agree to an extent). I usually define the following in my code and use it for fake call site documentation

#define byref
...
someFunc(byref x);

This of course doesn't enforce call site documentation. It just provides a very lame way of documenting it. I did some experimentation with a template which enforces call site documentation. This is more for fun than for actual production code though.

http://blogs.msdn.com/jaredpar/archive/2008/04/03/reference-values-in-c.aspx

JaredPar
I agree about the call-site not being self-documenting. However, realize that functions which modify reference parameters should almost always have an appropriate name. For example, Point.GetCoords(int and, mypoint.GetCoords(x, y);
strager
A: 

The former forces you to call the function with myfunc(&b) so the caller is aware that b will be modified

sometimes function could accept const pointer and caller will have wrong thinking that b will be modified.

My recommendation - prefer use references everywhere where it possible (ofcourse where it needed). In case with function argument - we get benefits:
- references can't be NULL - it help us to avoid errors and unnecessary asserts or checks.
- references have only one initialization point and in function boody you always know on what thing input parameter points.

I'm maintainer on large project. And in either cases I'm looking on function definition before call its. Ofcourse when I looking on function definition I see arguments definition by value, by reference, by const reference or by pointer.

But it seems like holy-war question, defferent peoples have different view on this point. E.g. google codding convension recomended use pointers in arguments which could be changed and allowed only const references: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Reference_Arguments

All parameters passed by reference must be labeled const.

bb
+2  A: 

I think I would disagre with @bb and @JaredPar and I lean to the opposite side of the fence. After years of trying to support other peoples C++ code, I often find problems lurking in non-obvious side effects of reference arguments. With C#, it is obvious since you have to prefix types of arguments with 'ref'/'out' but references are potentially confusing in C++. So, I like pointers because it's really clear something is coming back up. If you don't like points, C++ is not for you.

kenny
Ismael
+16  A: 

Pointers (ie. the '*') should be used where the passing "NULL" is meaningful. For example, you might use a NULL to represent that a particular object needs to be created, or that a particular action doesn't need to be taken. Or if it ever needs to be called from non-C++ code. (eg. for use in shared libraries)

eg. The libc function time_t time (time_t *result);

If result is not NULL, the current time will be stored. But if result is NULL, then no action is taken.

If the function that you're writing doesn't need to use NULL as a meaningful value then using references (ie. the '&') will probably be less confusing - assuming that is the convention that your project uses.

Andrew Edgecombe
Ah, good point. Now I don't feel as bad about using a reference instead. Much easier to write the function with a reference than a pointer. Thanks :)
Mark
A: 

In an ideal world it comes down to whether or not the parameter is an optional output. Do you want to allow the caller to pass NULL if they don't care about it? Then use a pointer. Otherwise a reference is a better choice.

Note that in both cases the language makes it cumbersome to document an output parameter. It's much better if the whole codebase is const correct, then the users can assume that any non-const reference or pointer parameter is an output.

Dan Olson
+1  A: 

I come down on the pointer side of the fence, for reasons cited here and elsewhere. However, I will say that whatever you decide, you need to be consistent and document it in your style guide.

Google C++ style guide bans non-const reference arguments.

jeffamaphone
A: 

One difference, like has been mentioned before, is you can't pass a null reference, but you can pass a null pointer.

Another thing, also mentioned already, when you call f(a,b) there could be confusion if the caller doesn't know that f could potentially change the value for b

However, yet another issue, which is rather subtle, but I still ran into it, is the semantics of references.

Pointers are passed by value, but references are not.

Which means, if you pass a parameter by pointer, you can change the pointer and make it point to something else.

Consider this:

void f1_ptr( type * a )
{
    a = new type(); //no change to passed parameters, you're changing the pointer which was passed by value
}

void f2_ptr( type * a )
{
    *a = some_other_value; //now you're changing the value of the parameter that was passed

   //or, if type is a class or struct:

   a->some_method_that_modifies_object(); //again, changing the parameter that was passed
}

But, when passing by reference, you can't change the reference to refer to another value. Once the reference is set, it can't be changed.

void f3_ref( type& a )
{
    a = type(); //the referred variable has also changed
}

//....

type obj = type( params );

f3_ref( obj ); //obj now changed

f1_ptr( &obj ); //obj doesn't change

f2_ptr( &obj ); //obj now changed
hasen j
In f2_ptr, a changes for f2_ptr's scope. In other words, obj is not modified when f2_ptr is called (assuming the original value of a (obj) isn't used in f2_ptr).
strager
A: 

I like passing by reference if NULL does not have significance, but I can see the arguments for both. If you're careful about coding you could probably eliminate the accidental pass-by-reference objection by making sure you always pass your variables by const reference, eg:

myfunc( const_cast< const int& >( a ) );

// Alternatively, this approach may require additional handling 
// in the function, but it's cleaner at call point
myfunc( boost::cref( a ) );

That's a lot of extra code for little benefit, though. As Kenny pointed out, C# addressed this from the opposite end (requiring specific passing by reference), but that's not an option for C++ (unless, for example, you wrote your functions to take a reference wrapper as their parameter, like boost::ref(param)), eg:

void myfunc( const boost::reference_wrapper< int >& a ) { ... }

Fixing the pointer problem is more problematic, though... there's no compile-time way to ensure the pointer is valid, so you end up with either run time problems for pointer issues, or run time checks, or both. Tis the nature of pointers.

Anyway, that's just my opinion, for what it's worth.

Nick
Right. But why would you take the reference_wrapper itself by reference, and not by value?
Because it's a class, and passing it by const reference is probably faster than copying it (although it is copyable). Both will work; this way is probably less overhead.
Nick
well, reference_wrapper weighs exactly as much as a pointer. I thought this much was obvious.
It wasn't obvious to me, but I haven't looked at the code, or analyzed the eventual compiled binary; I was relying on the idea that const ref will be at least as fast as value, and might be faster. If it's obviously identical, then there's no reason to choose ref for speed. :)
Nick
The other [minor] reason I prefer const ref to value is that if you accidentally modify the input value in the function, you'll get an error. Admittedly it's a small benefit, though.
Nick
+1  A: 

Something to note, if you are using stl functors, it is easier if the parameter matches the container value type.

void foo(Bar *);

void frobnicate(vector<Bar *> vecBars)
{
   for_each(vecBars.begin(), 
            vecBars.end(), 
            ptr_fun(&foo));
}

The above code is much harder if foo takes Bar&