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;
}
func1(x);
or:
void func2(unsigned long* val) {
*val = 5;
}
func2(&x);
IOW: Is there any reason to pick one over another?
-
1References are of course valuable , but i come from C , where pointers are everywhere. One has to be proficient with pointers first to understand the value of references.Jay D– Jay D2012年05月08日 19:43:27 +00:00Commented May 8, 2012 at 19:43
-
How does this fit in with a goal such as referential transparency from functional programming? What if you always want functions to return new objects and never internally mutate the state, especially not of variables passed to the function. Is there a way this concept is still used with pointers and references in a language like C++. (Note, I'm assuming someone already has the goal of referential transparency. I'm not interested in talking about whether or not it is a good goal to have.)ely– ely2013年09月30日 17:31:01 +00:00Commented Sep 30, 2013 at 17:31
-
Prefer references. User pointers when you don't have a choice.Ferruccio– Ferruccio2014年07月05日 13:14:21 +00:00Commented Jul 5, 2014 at 13:14
12 Answers 12
My rule of thumb is:
Use pointers if you want to do pointer arithmetic with them (e.g. incrementing the pointer address to step through an array) or if you ever have to pass a NULL-pointer.
Use references otherwise.
10 Comments
Base* b = new Derived())? This seems like a case that can't be handled without pointers.I really think you will benefit from establishing the following function calling coding guidelines:
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
constspecifier.
- Note: This means, among other things, that only out-values (see item 3) and values passed by value (see item 4) can lack the
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.
If a function argument is an out-value, then pass it by reference.
- Rationale: We don't want to break item 2...
Choose "pass by value" over "pass by const reference" only if the value is a POD (Plain old Datastructure) 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.
12 Comments
std::vector<>.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 (https://google.github.io/styleguide/cppguide.html#Reference_Arguments), 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.
3 Comments
Pointers
- A pointer is a variable that holds a memory address.
- A pointer declaration consists of a base type, an *, and the variable name.
- A pointer can point to any number of variables in lifetime
A pointer that does not currently point to a valid memory location is given the value null (Which is zero)
BaseType* ptrBaseType; BaseType objBaseType; ptrBaseType = &objBaseType;The & is a unary operator that returns the memory address of its operand.
Dereferencing operator (*) is used to access the value stored in the variable which pointer points to.
int nVar = 7; int* ptrVar = &nVar; int nVar2 = *ptrVar;
Reference
A reference (&) is like an alias to an existing variable.
A reference (&) is like a constant pointer that is automatically dereferenced.
It is usually used for function argument lists and function return values.
A reference must be initialized when it is created.
Once a reference is initialized to an object, it cannot be changed to refer to another object.
You cannot have NULL references.
A const reference can refer to a const int. It is done with a temporary variable with value of the const
int i = 3; //integer declaration int * pi = &i; //pi points to the integer i int& ri = i; //ri is refers to integer i – creation of reference and initialization
1 Comment
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.
2 Comments
const or non-const reference, but you can see if the parameter's passed ala &x vs. x, and use that convension to encode whether the parameter's liable to be modified. (That said, there are times when you'll want to pass a const pointer, so the convension's just a hint. Arguable suspecting something might be modified when it won't be is less dangerous than thinking it won't be when it will be....)Use a reference when you can, use a pointer when you have to. From C++ FAQ: "When should I use references, and when should I use pointers?"
Comments
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);
}
Comments
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.
Comments
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 semantic) highlighting.
1 Comment
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...
Comments
Pointers:
- Can be assigned
nullptr(orNULL). - At the call site, you must use
&if your type is not a pointer itself, making explicitly you are modifying your object. - Pointers can be rebound.
References:
- Cannot be null.
- Once bound, cannot change.
- Callers don't need to explicitly use
&. This is considered sometimes bad because you must go to the implementation of the function to see if your parameter is modified.
2 Comments
A reference is similar to a pointer, except that you don’t need to use a prefix ∗ to access the value referred to by the reference. Also, a reference cannot be made to refer to a different object after its initialization.
References are particularly useful for specifying function arguments.
for more information see "A Tour of C++" by "Bjarne Stroustrup" (2014) Pages 11-12