7

Possible Duplicate:
FAQ: How to pass objects to functions in C++?
Pointer vs. Reference

Hi all,
in c/c++, we can pass a object as call by reference or passing pointer of the object.
for example:
i want to create a function which will take string vector as input and output a map that contains some value for each string. the return value of the function is bool, which indicate success or failure.

function (call by reference)

bool calculateSomeValue( vector<string> input, map<string, double>& result)
{
//// bla bla bla
return true/false;
}

function (using pointer )

bool calculateSomeValue( vector<string> input, map<string, double>* result)
{
//// bla bla bla
return true/false;
}

which one is best? does any one have any idea of the pros and cons of these two options?

thanks in advance.

Community
  • 1
  • 1
user619237
  • 1,776
  • 3
  • 17
  • 19
  • 4
    A pointer to a reference? That's interesting... @user619237: Do a search for `pointers versus references` on StackOverflow and you'll get more answers than you ever wanted. :] – user541686 Feb 16 '11 at 08:27
  • 2
    http://stackoverflow.com/questions/114180/pointer-vs-reference – sinek Feb 16 '11 at 08:30
  • 2
    You don't even need to search, just take a look to the right at the "Related" section :) – sinek Feb 16 '11 at 08:32
  • 2
    Use exceptions so you can properly use the *return value* of a function to, oh I don't know, *return a value*. – GManNickG Feb 16 '11 at 08:37
  • @GMan: I'm not sure if it's just me, but I don't really understand what you mean... could you elaborate on it a bit? – user541686 Feb 16 '11 at 08:43
  • @Mehrdad: Success and failure of operations should not be part of normal program flow, that's why we use exceptions to split into an error-handling flow, where the error may be caught and stopped somewhere up the call stack. (Expected errors should be tested beforehand, or the exception caught.) A `bool` return type breaks this and makes it the callers job to check for errors, and forces unorthodox value returns from functions. – GManNickG Feb 16 '11 at 08:48
  • @GMan: Ohhhh I see -- it was a reference to the statement `which indicate success or failure`. I was wondering how it was related to pointers; now it makes sense, thanks. :) – user541686 Feb 16 '11 at 08:51
  • 1
    @GMan: who says the bool here is a success/failure indicator (EDIT: ok, the question, still) - it might as easily have been some part of the resultant information, such as whether the result set contains inf or nan numbers ;-P. Anyway, there are certainly many times when a single function should affect many variables, in which case you either start creating silly little tuples (getting easier in C++0x), a painfully ad-hoc struct, or have multiple non-const by-ref-or-pointer parameters, but you can't very cleanly pack them into the result. – Tony Delroy Feb 16 '11 at 09:00
  • @Tony: Tuples all the way, not exactly difficult with Boost. Boost.Optional is also helpful here. – GManNickG Feb 16 '11 at 09:02
  • Its not clear that this question IS a duplicate. The other question dealt explicitly with & vs * when the parameter WAS being modified. – Chris Becke Feb 16 '11 at 09:35
  • Actually, I think this is a dupe of the FAQ entry __[How to pass objects to functions in C++?](http://stackoverflow.com/questions/2139224/how-to-pass-objects-to-functions-in-c)__. – sbi Feb 16 '11 at 09:53

7 Answers7

11

This is a matter of style. At Google (see Google C++ style guidelines), the following would be preferred:

bool CalculateSomeValue(
    const vector<string>& input, map<string, double>* result);

This is because using a pointer requires the explicit use of an ampersand at the call site:

 CalculateSomeValue(input, &result);

As opposed to the way it would be invoked with a reference type:

 CalculateSomeValue(input, result);

By forcing the use of an ampersand in cases where parameters are modified, it is clear at the call site what will happen. When using references, it becomes necessary to lookup the documentation for each and every function to know whether it has the potential to modify its input parameters.

However, the use of a pointer has its downsides, too. In particular, the use of a pointer means that you shift responsibility of handling null from the caller where the pointer would be dereferenced (if the variable is a pointer and not merely an address-of expression with a local variable) to the function. That is, when using a pointer type, CalculateSomeValue needs to check for nullptr (or needs to clearly document that it requires this checking in the caller), whereas the use of a reference type is self-documenting and clearly indicates that a non-null reference is expected.

For this particular situtation, I personally highly recommend a hybrid approach:

bool CalculateSomeValue(
   const std::vector<std::string>& input,
   Output<map<string, double>> result);

... where Output<T> is created by a function with the signature:

 template<typename T> Output<T> WriteTo(T& output_ref);

... and where Output<T> overloads operators ->, *, etc. This basically forces the call sites to be explicit in the fact that the input will be mutated by requiring:

 CalculateSomeValue(input, WriteTo(result));

... as opposed to:

 CalculateSomeValue(input, result);

... while simultaneously gaining the non-null semantics/syntax of references.

Michael Aaron Safyan
  • 93,612
  • 16
  • 138
  • 200
  • 1
    A notable exception IMHO: const references are preferred over const pointers. – user541686 Feb 16 '11 at 08:38
  • Yes. The OP was asking about an output result (or at least that is how I interpreted the question). You will notice in my answer that I use a const reference for the input parameter. – Michael Aaron Safyan Feb 16 '11 at 08:40
  • @Michael: Oops, my bad -- I totally missed the phrase "where parameters are **modified** ". – user541686 Feb 16 '11 at 08:42
  • NP. I've certainly made similar mistakes and worse myself. – Michael Aaron Safyan Feb 16 '11 at 08:46
  • @Michael: I also follow this practice and find it useful, though it's worth pointing out that the C++ FAQ lite disagrees (http://www.parashift.com/c++-faq-lite/references.html#faq-8.6). There are other situations where passing by pointer may be done despite the variable not being potentially modified: the association is imperfect (though I still find it better to err on the side of suspecting change). – Tony Delroy Feb 16 '11 at 08:54
  • @Tony, thanks for pointing that out (indeed, that is how I coded before joining Google). I think there is something to be said for both. It is too bad that one must choose between the assurance that the parameter can not be NULL on the one hand (a major advantage of using references) and the explicit call syntax on the other (an advantage of this coding style). The vigilant use of 'if (!param) { LOG(DFATAL) << "param cannot be NULL."; return false; }' as well as unit tests checking for debug death catch most issues, though. – Michael Aaron Safyan Feb 16 '11 at 09:09
  • @Michael: yes, it's unfortunately C++0x isn't introducing a notations/keyword(s) for "out" parameters that can be used and cross-referenced at the caller and callee sights... could still be backwards compatible when the callee doesn't use the notation. Maybe one day. – Tony Delroy Feb 16 '11 at 09:15
  • 1
    `-1`. Google has been taking a lot of flak for their style guide, and IMO rightly so. This rule is absolutely nonsense, because even seeing `&result` I still don't know whether the parameter is `map*` or `const map*` (note the `const`). __You will have to look at a function's declaration to actually understand how the parameters are passed.__ This might be called a deficiency of C++, but it is what we have and have to live with. See http://stackoverflow.com/questions/2139224/ for what I consider sensible rules about parameter passing. – sbi Feb 16 '11 at 10:01
  • thanks guys for all these information. – user619237 Feb 16 '11 at 16:35
  • @sbi, in the case where it is const, though, we would use a reference. – Michael Aaron Safyan Feb 18 '11 at 05:56
1

if the argument is not optional, i find c++ many devs prefer to pass by reference. however, many like to pass by pointer solely for the visual cue. this is a bit of a holdover from c which erodes as the program grows to deal with mixed usage of references and pointers.

you can assume a reference is not null, but you should not assume that for pointers. in that case, you'll have to introduce the precondition scaffolding/checks to make sure somebody upstream did not believe the argument was optional -- if you're defensive.

personally, i prefer to pass by reference, and to use descriptive method/function/variable names (if you only detail the labels, then people have to go to the docs more frequently). this keeps the program's intention clear, and avoids the extra written checks. get* or update* may be more obvious than calculate*.

using references is consistent, well defined, and produces simpler programs since you are not dealing with mixed variable/argument types.

it really doesn't make a significant difference which you choose in this case, just be consistent in your usage. another cue i use is to put modified parameters in the same place. specifically, they precede constant arguments.

justin
  • 104,054
  • 14
  • 179
  • 226
0
bool calculateSomeValue( vector<string> input, map<string, double>&* result)

Pointer to reference? This would not even compile. First one is correct and only the correct can be best!

struct A {};

void f(A & *a) {}

Compile gives rrror:

prog.cpp:7: error: cannot declare pointer to ‘struct A&’

Ideone sample : http://www.ideone.com/8PJA5

Nawaz
  • 353,942
  • 115
  • 666
  • 851
0

Your second code sample seems to be incorrect, as you're trying to accept a pointer to a reference, which shouldn't compile.

Passing by reference and passing a pointer are just as efficient (someone correct me if I'm wrong, but it is my understanding that a reference is essentially an automatically created pointer that is then seamlessly dereferenced), but passing by reference is recommended as it is safer:

  • You cannot have a null reference.
  • You can't change the address referenced, whereas a pointer would allow you to.

Some prefer the explicit pointer syntax that makes it clear that it's a pointer to an object passed in (as you must dereference).

Andrew Marshall
  • 95,083
  • 20
  • 220
  • 214
  • @Andrew: I once said the sentence "you cannot have a null reference" and almost got beaten to death for it, because `(int&)(*(int*)NULL)` is technically a null reference. I agree with what you said, but just warning you that people might freak out at that sentence. :) – user541686 Feb 16 '11 at 08:35
  • @Mehrdad: That's a false retort, because dereferencing a null pointer leads to undefined behavior. In other words, if I have a function `void f(int& i)`, I know that `i` will always refer an `int`. If you say, "`i` might not be, pass `*((int*)0)`" (by the way, the final cast to `int&` is redundant), then you've defeated yourself because you cannot assume any program behavior after that expression is evaluated (you cannot access the `i` inside `f` because "call a function" is meaningless). In other words, because of UB, the term "reference" is meaningless, and cannot be said to be null. – GManNickG Feb 16 '11 at 08:51
  • Or as an analogy, that's like me saying "Wearing a seat belt saves lives" and you retorting "Not if you don't wear them!". If you don't wear it, the statement cannot apply. – GManNickG Feb 16 '11 at 08:54
  • @GMan: I agree that it's a lousy attempt at finding an exception, but see [this thread](http://stackoverflow.com/questions/4715740/why-is-a-c-reference-considered-safer-than-a-pointer/4715756#4715756) as an example of where this was used against me. :\ – user541686 Feb 16 '11 at 08:54
  • @Mehrdad: Yes, I remember those comments. The retort though, was for the claim "references are safer" (which I do agree with). – GManNickG Feb 16 '11 at 08:57
  • Haha I think I'll just stop before I post another twenty comments like last time... it's past my bedtime. xD Thanks for the discussion though! – user541686 Feb 16 '11 at 09:01
  • 1
    Yes, it is an unfortunate tradeoff; being explicit in the calling and having the assurance that it cannot be NULL. It would be nice if there were an explicit reference call syntax that provided such an assurance. On the other hand, references shift where the dereference occurs. Checking that the input is non-NULL can make the error occur closer to the call site that passed in the NULL pointer. – Michael Aaron Safyan Feb 16 '11 at 09:13
0

The best solution doesn't exist. It goes from case to case.

For example, next can be better in some situations :

map<string, double> calculateSomeValue( const vector<string> &input )
{
  map<string, double> res;
// do something with input to form the output
  return res;
}

But, if you can, prefer to use standard algorithms

BЈовић
  • 62,405
  • 41
  • 173
  • 273
  • Return values are generally a good way to go, but in the OPs example the return type is void and not bool, so you would still need to have a way to return that other value. – Michael Aaron Safyan Feb 16 '11 at 08:35
  • @Michael In the OPs example, return values are of type bool, and I am not sure I understand your comment. Can you clarify? – BЈовић Feb 16 '11 at 08:40
  • 1
    I am saying that using a return-value for the result (instead of passing in a reference or a pointer into which to write the result) is an equivalent alternative when the return-type in the pointer/reference case had been void. In this case, where the return value is already used for something else, one is forced to use output parameters or to create an encapsulating object that contains all the information to be returned. – Michael Aaron Safyan Feb 16 '11 at 08:43
  • @Michael As you said : a matter of style. What I said is : one size doesn't fit all. – BЈовић Feb 16 '11 at 09:06
0

I'm assuming the second one is supposed to be just by point and not a pointer to a reference.

The decision between the two is only a matter of style and taste. The compiled result of both lines is likely to be the same.

Usually for output parameters, C++ style guides say it should be by pointer.

shoosh
  • 76,898
  • 55
  • 205
  • 325
0

The only time to use references is when implementing the standard operators that require them.

However, outside of that, Pointers should always be preferred over references for any application methods.

  • User objects are frequently stored stored in pointers, smart or otherwise. The constraints on references to always be valid is just too strict when objects are being created on demand. This makes reference parameters inconvenient to use as one needs to do a clumsy operation to pass the value. referenceFunc( (*pObj) );

  • Passing by reference is a cheap substitute for trying to implement a contract paradigm. Which c++ doesn't support.

  • All the (*somePtr) operations on that pass-by-reference will imply means youre going to get null pointer's to debug anyway, just more obscured as the null pointer won't look like a pointer.

  • Nevermind the maintenance issue when programmers cannot tell by simple examination which parameters to a function might change.

Chris Becke
  • 34,244
  • 12
  • 79
  • 148