views:

4965

answers:

11

What would be better practice when giving a function the original variable to work with:

unsigned long x = 4;

void func1(unsigned long& val) { val = 5; } func(x);

or: void func2(unsigned long* val) { *val = 5; } func2(&x);

IOW: Is there any reason to pick one over another?

+36  A: 

My rule of thumb is:

Use pointers if you want to do arithmetic with them or if you ever have to pass a NULL-pointer.

Use references otherwise.

Nils Pipenbrinck
Excelent point regarding a pointer being NULL. If you have a pointer parameter then you must either check explicitly that it is not NULL, or search all usages of the function to be sure that it is never NULL. This effort is not required for references.
Richard Corden
Explain what you mean by arithmetic. A new user may not understand that you want to adjust what the pointer is pointing at.
Martin York
Martin,By arithmetic I mean that you pass a pointer to a structure but know that it's not a simple structure but an array of it. In this case you could either index it using [] or do arithmetic by using ++/-- on the pointer. That's the difference in a nutshell.
Nils Pipenbrinck
Martin, You can only do this with pointers directly. Not with references. Sure you can take a pointer to a reference and do the same thing in practice, but if you do so you end with very dirty code..
Nils Pipenbrinck
+4  A: 

You cannot store references, but you can store pointers. In any code that would need to store a pointer to an object in order to use it later on, I would prefer passing a pointer.

If the passed object is only intended to be used for the duration of the call, I would opt for the reference.

xtofl
You can store references, however they have to be initialized. For example a reference can be a member of a class, but it then needs to be initialized in the member list for all of the constructors.
1800 INFORMATION
You can also have a reference passed in and then grab a pointer to the reference. Not saying this is a good idea, but it is a possible way to 'store' a reference :)
workmad3
-1 for stating that you can't store references, that is simply incorrect and (thus) misleading in my opinion.
unwind
+1  A: 

@xtofl,

Sure you can store references. Take a look:

struct foo
{
    int member;
};

struct bar
{
    foo & f;
    int othermember;

    bar (foo & a_foo) : f(a_foo) {}
};

int main (int argc, char **args)
{
    foo f;
    f.member = 1;
    bar b(f);
    printf ("%d\n", b.f.member); // prints 1
}
Nils Pipenbrinck
xtofl
you can write a simple wrapper-class to do this.
Nils Pipenbrinck
which kind of proves xtofl's point since you'd be createing a dynamic container of wrapper classes, not of references.
QBziZ
The nastiest part of this is what happens when the referred to value goes out of scope. At least with a pointer, the caller recognises that he has to pass in a pointer and that it is non-const.
Jon Trauntvein
+10  A: 

I really think you will benefit from establishing the following function calling coding guidelines:

  1. As in all other places, always be const-correct.

    • Note: This means, among other things, that only out-values (see item 3) and values passed by value (see item 4) can lack the const specifier.
  2. Only pass a value by pointer if the value 0/NULL is a valid input in the current context.

    • Rationale 1: As a caller, you see that whatever you pass in must be in a usable state.

    • Rationale 2: As called, you know that whatever comes in is in a usable state. Hence, no NULL-check or error handling needs to be done for that value.

    • Rationale 3: Rationales 1 and 2 will be compiler enforced. Always catch errors at compile time if you can.

  3. If a function argument is an out-value, then pass it by reference.

    • Rationale: We don't want to break item 2...
  4. Choose "pass by value" over "pass by const reference" only if the value is a POD or small enough (memory-wise) or in other ways cheap enough (time-wise) to copy.

    • Rationale: Avoid unnecessary copies.
    • Note: small enough and cheap enough are not absolute measurables.
Johann Gerell
paercebal
Item 1 covers the case you describe.
Johann Gerell
It's a bit hard to pass an out-parameter by reference if it's not default-constructible. That's quite common in my code - the whole reason to have a function create that out-object is because it's non-trivial.
MSalters
A: 

Pass by const reference unless there is a reason you wish to change/keep the contents you are passing in.

This will be the most efficient method in most cases.

Make sure you use const on each parameter you do not wish to change, as this not only protects you from doing something stupid in the function, it gives a good indication to other users what the function does to the passed in values. This includes making a pointer const when you only want to change whats pointed to...

NotJarvis
+3  A: 

This ultimately ends up being subjective. The discussion thus far is useful, but I don't think there is a correct or decisive answer to this. A lot will depend on style guidelines and your needs at the time.

While there are some different capabilities (whether or not something can be NULL) with a pointer, the largest practical difference for an output parameter is purely syntax. Google's C++ Style Guide (http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml), for example, mandates only pointers for output parameters, and allows only references that are const. The reasoning is one of readability: something with value syntax should not have pointer semantic meaning. I'm not suggesting that this is necessarily right or wrong, but I think the point here is that it's a matter of style, not of correctness.

Aaron N. Tubbs
A: 

A reference is an implicit pointer. Basically you can change the value the reference points to but you can't change the reference to point to something else. So my 2 cents is that if you only want to change the value of a parameter pass it as a reference but if you need to change the parameter to point to a different object pass it using a pointer.

+2  A: 

You should pass a pointer if you are going to modify the value of the variable. Even though technically passing a reference or a pointer are the same, passing a pointer in your use case is more readable as it "advertises" the fact that the value will be changed by the function.

Max Caceres
+1  A: 

If you have a parameter where you may need to indicate the absence of a value, it's common practice to make the parameter a pointer value and pass in NULL.

A better solution in most cases (from a safety perspective) is to use boost::optional. This allows you to pass in optional values by reference and also as a return value.

// Sample method using optional as input parameter
void PrintOptional(const boost::optional<std::string>& optional_str)
{
    if (optional_str)
    {
       cout << *optional_str << std::endl;
    }
    else
    {
       cout << "(no string)" << std::endl;
    }
}

// Sample method using optional as return value
boost::optional<int> ReturnOptional(bool return_nothing)
{
    if (return_nothing)
    {
       return boost::optional<int>();
    }

    return boost::optional<int>(42);
}
Kiley Hykawy
A: 

Consider C#'s out keyword. The compiler requires the caller of a method to apply the out keyword to any out args, even though it knows already if they are. This is intended to enhance readability. Although with modern IDEs I'm inclined to think that this is a job for syntax (or symantic) highlighting.

Daniel Earwicker
A: 

Good article below: http://www.embedded.com/story/OEG20010311S0024

I recommend it.

reddy