Explore more and find the answer to determine how to pass in old post (sorry for duplicate)
If the function intends to change the argument as a side effect, take
it by non-const reference.
If the function doesn't modify its
argument and the argument is of primitive type, take it by value.
Otherwise take it by const reference, except in the following cases
If the function would then need to make a copy of the const reference
anyway, take it by value.
[Original Post is Below]
I'd like to summarize the use of passing by value, const value, reference, const reference, pointer, const pointer and please correct me and give me your suggestions.
As for reference and pointer, use const if possible (thanks to all).
There is no performance difference between passing by reference and pointer.
When the size is not larger than a pointer (thanks to Mark Ransom), pass by value.
And some questions:
I seldom see passing by const value. Is it useful or the compiler will detect the const-ness in passing by value?
The const reference takes too much space. Can I just use passing by value? Will the modern compilers optimize it to not sacrifice the performance?
According the the article "Want Speed? Pass by Value" juanchopanza mentioned, I add one more item.
If you will copy your arguments, pass them by value and let the compiler do the copying other than passing them by const reference and doing the copy by yourself in the function body.
Thanks a lot!
I seldom see passing by const value. Is it useful or the compiler will detect the const-ness in passing by value?
Passing by const value doesn't really exist. When you pass by value, you can't modify the value in such a way that the changes will be visible outside of the subroutine. This is because when you pass by value, a copy is made of the original value and that copy is used in the function.
The const reference takes too much space. Can I just use passing by
value? Will the modern compilers optimize it to not sacrifice the
performance?
Passing by (const) reference is not the same as passing by value. When you pass by reference the value is NOT copied, a memory location is simply supplied and thus you may 'modify' (indirectly) the value that you pass by reference.
Take for example, the following:
void byValue(int x) {
x += 1
}
void byRef(int &x) {
x += 1
}
// ...
{
y = 10;
byValue(y);
cout << y << endl // Prints 10
byRef(y);
cout << y << endl; // Prints 11
}
// ...
Use const as much as possible.
Passing const where necessary is always a good idea. It helps code readability, lets others know what will happen to the values they pass to the method, and helps the compiler catch any mistakes you may make in modifying the value inside the method.
There is no performance difference between passing by reference and pointer.
A negligible amount, if any. The compiler will take care of the details here. It saves you the effort of creating a pointer, and it nicely dereferences it for you.
When the size is not larger than a word, pass by value.
As Mark points out, you do this if the value is smaller than a pointer. Pointers are different sizes on 32bit and 64bit systems (hence the name) and so this is really at your discretion. I'm a fan of passing pointers for nearly everything except the primitive types (char, int8_t, int16_t, float, etc), but that is just my opinion.
Related
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What's the difference between passing by reference vs. passing by value?
I read that in C arguments are passed by value, but what's is the difference between passing arguments by value (like in C) or by refencence (like C++ - C#)?
What's the difference between a pointer and a reference?
void with_ptr(int *i)
{ *i = 0; }
void with_ref(int &i)
{ i = 0; }
In these cases are modified both value? If yes, why C++ allows to pass arguments by reference? I think it is not clear inside the function that the i value could be modified.
what's is the difference between passing arguments by value or by reference
If you pass by value, changes to the variable will be local to the function, since the value is copied when calling the function. Modifications to reference arguments will propagate to the original value.
What's the difference between a pointer and a reference?
The difference is largely syntactic, as you have seen in your code. Furthermore, a pointer can be reassigned to point to something else (unless it’s declared const), while a reference can’t; instead, assigning to a reference is going to assign to the referenced value.
I think it is not clear inside the function that the i value could be modified.
On the contrary, it’s absolutely clear: the function signature tells you so.
There’s actually a case to be made that it’s not clear outside the function. That’s why original versions of C# for instance mandated that you explicitly annotate any by-reference calling with ref (i.e. f(ref x) instead of plain f(x)). This would be similar to calling a function in C++ using f(&x) to make it clear that a pointer is passed.
But in recent versions of C#, the use of ref for calling was made optional since it didn’t confer enough of an advantage after all.
Consider this:
1) Passing by reference provides more simple element access i instead of *i
2) Generally you cannot pass null reference to a method, but can pass a null pointer
3) You can't change the address of reference, but can change it for a pointer(although, as pointer itself passed by value, this change will be discarded upon function exit)
Hope, this helped a bit
Actually, in the first case, you can't modify the argument. The pointer itself is immutable, you can only modify the value it points to.
If yes, why C++ allows to pass arguments by reference?
Because pointers can very easily be miss-used. References should almost always be prefered. For your case, what if you pass a NULL to with_ptr? You'll get undefined behavior, which is not possible if you use with_ref.
I think it is not clear inside the function that the i value could be modified.
It is very clear. If you see a function that takes a parameter by non-const reference, you can assume it will be changed.
I think that a method can only change an argument's value, if this is passed by reference. If you pass a argument by value in a method, then whatever change you make to its value, this will no be available in the parent method.
As far as I know, I think the reference is safer to use in a sense that it can't be modified (always points to the same thing), and should be initialized if it's a local variable. Pointer, however, can be change to point to somewhere else.
int x = 10;
int &y = x;
int *p = &x;
p++; //Legal if you know what's next
y++; // Increases the value of x. Now x = y = 11;
As my two cents, I think reference variables are mere alternative names for the same memory address by which it was initialized. This also explains pretty nice:
http://www.dgp.toronto.edu/~patrick/csc418/wi2004/notes/PointersVsRef.pdf
There are many questions about "when do I use reference and when pointers?". They confused me a little bit. I thought a reference wouldn't take any memory because it's just the address.
Now I made a simple Date class and showed them the community of code-review. They told me not to use the reference in the following example. But why?
Someone told me that it'll allocate the same memory a pointer would allocate. That's the opposite of what I learned.
class A{
int a;
public:
void setA(const int& b) { a = b; } /* Bad! - But why?*/
};
class B{
int b;
public:
void setB(int c) { b = c; } /* They told me to do this */
};
So when do I use references or pointers in arguments and when just a simple copy? Without the reference in my example, is the constant unnecessary?
It is not guaranteed to be bad. But it is unnecessary in this specific case.
In many (or most) contexts, references are implemented as pointers in disguise. Your example happens to be one of those cases. Assuming that the function does not get inlined, parameter b will be implemented "under the hood" as a pointer. So, what you really pass into setA in the first version is a pointer to int, i.e. something that provides indirect access to your argument value. In the second version you pass an immediate int, i.e. something that provides direct access to your argument value.
Which is better and which is worse? Well, a pointer in many cases has greater size than an int, meaning that the first variant might passes larger amount of data. This might be considered "bad", but since both data types will typically fit into the hardware word size, it will probably make no appreciable difference, especially if parameters are passed in CPU registers.
Also, in order to read b inside the function you have to dereference that disguised pointer. This is also "bad" from the performance point of view.
These are the formal reasons one would prefer to pass by value any parameters of small size (smaller or equal to pointer size). For parameters or bigger size, passing by const reference becomes a better idea (assuming you don't explicitly require a copy).
However, in most cases a function that simple will probably be inlined, which will completely eliminate the difference between the two variants, regardless of which parameter type you use.
The matter of const being unnecessary in the second variant is a different story. In the first variant that const serves two important purposes:
1) It prevents you from modifying the parameter value, and thus protects the actual argument from modification. If the reference weren't const, you would be able to modify the reference parameter and thus modify the argument.
2) It allows you to use rvalues as arguments, e.g. call some_obj.setA(5). Without that const such calls would be impossible.
In the second version neither of this is an issue. There's no need to protect the actual argument from modification, since the parameter is a local copy of that argument. Regardless of what you do to the parameter, the actual argument will remain unchanged. And you can already use rvalues as arguments to SetA regardless of whether the parameter is declared const or not.
For this reason people don't normally use top-level const qualifiers on parameters passed by value. But if you do declare it const, it will simply prevent you from modifying the local b inside the function. Some people actually like that, since it enforces the moderately popular "don't modify original parameter values" convention, for which reason you might sometimes see top-level const qualifiers being used in parameter declarations.
If you has light-weight type like a int or long you should use passing by value, because there won't be additional costs from work with references. But when you passing some heavy types, you should use references
I agree with the reviewer. And here's why:
A (const or non-const) reference to a small simple type, such as int will be more complex (in terms of number of instructions). This is because the calling code will have to pass the address of the argument into setA, and then inside setA the value has to be dereferenced from the address stored in b. In the case where b is a plain int, it just copies the value itself. So there is at least one step of a memory reference in saving. This may not make much of a difference in a long runtime of a large program, but if you keep adding one extra cycle everywhere you do this, then it does soon add up to noticeably slower.
I had a look at a piece of code that went something like this:
class X
{
vector v;
public:
...
void find(int& index, int b);
....
}
bool X::find(int &index, int b)
{
while(v[index] != b)
{
if (index == v.size()-1)
{
return false;
}
index++;
}
return true;
}
Rewriting this code to:
bool X::find(int &index, int b)
{
int i = index;
while(v[i] != b)
{
if (i == v.size()-1)
{
index = i;
return false;
}
i++;
}
index = i;
return true;
}
meant that this function went from about 30% of the total execution of some code that called find quite a bit, to about 5% of the execution time of the same test. Because the compiler put i in a register, and only updated the reference value when it finished searching.
References are implemented as pointers (that's not a requirement, but it's universally true, I believe).
So in your first one, since you're just passing an "int", passing the pointer to that int will take about the same amount of space to pass (same or more registers, or same or more stack space, depending on your architecture), so there's no savings there. Plus now you have to dereference that pointer, which is an extra operation (and will almost surely cause you to go to memory, which you might not have to do with the second one, again, depending on your architecture).
Now, if what you're passing is much larger than an int, then the first one could be better because you're only passing a pointer. [NB that there are cases where it still might make sense to pass by value even for a very large object. Those cases are usually when you plan to create your own copy anyway. In that case, it's better to let the compiler do the copy, because the overall approach may improve it's ability to optimize. Those cases are very complex, and my opinion is that if you're asking this question, you should study C++ more before you try to tackle them. Although they do make for interesting reading.]
Passing primitives as const-reference does not save you anything. A pointer and an int use the same amount of memory. If you pass a const-reference, the machine will have to allocate memory for a pointer and copy the pointer address, which has the same cost as allocating and copying an integer. If your Date class uses a single 64-bit integer (or double) to store the date, then you don't need to use const-reference. However, if your Data class becomes more complex and stores additional fields, then passing the Date object by const-reference should have a lower cost than passing it by value.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What's the difference between passing by reference vs. passing by value?
I read that in C arguments are passed by value, but what's is the difference between passing arguments by value (like in C) or by refencence (like C++ - C#)?
What's the difference between a pointer and a reference?
void with_ptr(int *i)
{ *i = 0; }
void with_ref(int &i)
{ i = 0; }
In these cases are modified both value? If yes, why C++ allows to pass arguments by reference? I think it is not clear inside the function that the i value could be modified.
what's is the difference between passing arguments by value or by reference
If you pass by value, changes to the variable will be local to the function, since the value is copied when calling the function. Modifications to reference arguments will propagate to the original value.
What's the difference between a pointer and a reference?
The difference is largely syntactic, as you have seen in your code. Furthermore, a pointer can be reassigned to point to something else (unless it’s declared const), while a reference can’t; instead, assigning to a reference is going to assign to the referenced value.
I think it is not clear inside the function that the i value could be modified.
On the contrary, it’s absolutely clear: the function signature tells you so.
There’s actually a case to be made that it’s not clear outside the function. That’s why original versions of C# for instance mandated that you explicitly annotate any by-reference calling with ref (i.e. f(ref x) instead of plain f(x)). This would be similar to calling a function in C++ using f(&x) to make it clear that a pointer is passed.
But in recent versions of C#, the use of ref for calling was made optional since it didn’t confer enough of an advantage after all.
Consider this:
1) Passing by reference provides more simple element access i instead of *i
2) Generally you cannot pass null reference to a method, but can pass a null pointer
3) You can't change the address of reference, but can change it for a pointer(although, as pointer itself passed by value, this change will be discarded upon function exit)
Hope, this helped a bit
Actually, in the first case, you can't modify the argument. The pointer itself is immutable, you can only modify the value it points to.
If yes, why C++ allows to pass arguments by reference?
Because pointers can very easily be miss-used. References should almost always be prefered. For your case, what if you pass a NULL to with_ptr? You'll get undefined behavior, which is not possible if you use with_ref.
I think it is not clear inside the function that the i value could be modified.
It is very clear. If you see a function that takes a parameter by non-const reference, you can assume it will be changed.
I think that a method can only change an argument's value, if this is passed by reference. If you pass a argument by value in a method, then whatever change you make to its value, this will no be available in the parent method.
As far as I know, I think the reference is safer to use in a sense that it can't be modified (always points to the same thing), and should be initialized if it's a local variable. Pointer, however, can be change to point to somewhere else.
int x = 10;
int &y = x;
int *p = &x;
p++; //Legal if you know what's next
y++; // Increases the value of x. Now x = y = 11;
As my two cents, I think reference variables are mere alternative names for the same memory address by which it was initialized. This also explains pretty nice:
http://www.dgp.toronto.edu/~patrick/csc418/wi2004/notes/PointersVsRef.pdf
This might be a stupid question, but I notice that in a good number of APIs, a lot of method signatures that take integer parameters that aren't intended to be modified look like:
void method(int x);
rather than:
void method(const int &x);
To me, it looks like both of these would function exactly the same. (EDIT: apparently not in some cases, see answer by R Samuel Klatchko) In the former, the value is copied and thus can't change the original. In the latter, a constant reference is passed, so the original can't be changed.
What I want to know is why one over the other - is it because the performance is basically the same or even better with the former? e.g. passing a 16-bit value or 32-bit value rather than a 32-bit or 64-bit address? This was the only logical reason I could think of, I just want to know if this is correct, and if not, why and when one should prefer int x over const int &x and vice versa.
It's not just the cost of passing a pointer (that's essentially what a reference is), but also the de-referencing in the called method's body to retrieve the underlying value.
That's why passing an int by value will be virtually guaranteed to be faster (Also, the compiler can optimize and simply pass the int via processor registers, eliminating the need to push it onto the stack).
To me, it looks like both of these would function exactly the same.
It depends on exactly what the reference is to. Here is an admittedly made up example that would change based on whether you pass a reference or a value:
static int global_value = 0;
int doit(int x)
{
++global_value;
return x + 1;
}
int main()
{
return doit(global_value);
}
This code will behave differently depending on whether you have int doit(int) or int doit(const int &)
Integers are usually the size of the processor's native word and can pass easily into a registers. From this perspective, there is no difference between passing by value or passing by constant reference.
When in doubt, print the assembly language listing for your functions to find out how the compiler is passing the argument. Print out for both pass by value and pass by constant reference.
Also, when passing by value, the function can modify the copy. When passing by constant reference, the function cannot modify the variable (it's marked as const).
There will probably be a very, very small de-optimization for passing by reference, since at the very least one dereference will need to occur to get the actual value (unless the call is inlined, the compiler cannot simply pass the value due to the fact that the call site and function might be separately compiled, and it's valid and well-defined to cast away the const for a passed parameter that isn't actually const itself - see What are the benefits to passing integral types by const ref). Note, however, that the 'de-optimization' is likely to be so small as to be difficult to measure.
Most people seem to dislike pass-by-const-ref for built-ins because of this (some very much). However, I think that it it might be preferable in some cases if you want the compiler to assist you in ensuring that the value isn't accidentally changed within the function. It's not a big thing, but sometimes it might help.
Depending on the underlying instruction set, an integer parameter can be passed as register or on the stack. Register is definitely faster than memory access, which would always be required in case of const refs (considering early cache-less architectures)
You cannot pass an int literal as a const int&
Explicit type-casts allow you cast a const int& into * (const int *) opening the possibility to change the value of the passed reference
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?
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.
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 const specifier.
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.
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.
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
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.
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);
}
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?"
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.
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.
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...
Pointers:
Can be assigned nullptr (or NULL).
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.
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