开发者

Call by reference vs Pointer argument [duplicate]

This question already has answers here: Closed 11 years ago.

Possible Duplicate:

开发者_JS百科 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.


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.


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.


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


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).


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


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜