If all a function needs to do with a parameter is see its value, shouldn't you always pass that parameter by constant reference?
A colleague of mine stated that it doesn't matter for small types, but I disagree.
So is there any advantage to do this:
void function(char const& ch){ //<- const ref
if (ch == 'a'){
DoSomething(ch);
}
return;
}
over this:
void function(char ch){ //<- value
if (ch == 'a'){
DoSomething(ch);
}
return;
}
They appear to be the same size to me:
#include <iostream>
#include <cstdlib>
int main(){
char ch;
char& chref = ch;
std::cout << sizeof(ch) << std::endl; //1
std::cout << sizeof(chref) << std::endl; //1
return EXIT_SUCCESS;
}
But I do not know if this is always the case.
I believe I'm right, because it does not produce any additional overhead and it is self documenting.
However, I want to ask the community if my reasoning and assumptions are correct?
Your colleague is correct. For small types (char, int) it makes no sense to pass by reference, when the variable is not to be modified. Passing by value would be better, as size of pointer (used in case of passing by reference) is about the size of small types.
And moreover, passing by value, is lesser typing, as well as slightly more readable.
Even though the sizeof(chref) is the same as sizeof(ch), passing character by reference does take more bytes on most systems: although the standard does not say anything specific about the implementation of references, an address (i.e. a pointer) is regularly passed behind the scenes. With optimization on, it probably would not matter. When you code template functions, items of unknown type that will not be modified should always be passed by const reference.
As far as small types go, you can pass them by value with a const qualifier to emphasize the point that you aren't going to touch the argument through the signature of your function:
void function(const char ch){ //<- value
if (ch == 'a'){
DoSomething(ch);
}
return;
}
For small values, the cost of creating a reference and dereferencing it is likely to be greater than the cost of copying it (if there is a difference at all). This is especially true when you consider that reference parameters are pretty much always implemented as a pointer. Both document equally well if you just declare your value as const (I'm using this value for input only and it will not be modified). I generally just make all of the standard built-in types by const value and all user-defined / STL types as const &.
Your sizeof example is flawed because chref is just an alias for ch. You'd get equal results for sizeof(T) for any type T.
The sizes are not the same as passed. The result depends on the ABIs calling convention, but the sizeof(referenceVariable) produces the sizeof(value).
If all a function needs to do with a parameter is see its value, shouldn't you always pass that parameter by constant reference?
That's what I do. I know people disagree with me, and argue for passing small builtins by value, or prefer to omit the const. Passing by reference can add instructions and/or consume more space. I pass this way for consistency, and because always measuring the best way to pass for any given platform is a lot of hassle to maintain.
There isn't an advantage beyond readability (if that's your preference). Performance could suffer very slightly, but it will not be a consideration in most cases.
Passing these small builtins by value is more common. If passing by value, you can const qualify the definition (independent of the declaration).
My recommendation is that the vast majority of teams should simply choose one way to pass and stick with it, and performance should not influence that unless every instruction counts. The const never hurts.
In my opinion, your general approach of passing by const reference is a good practice (but see below for some caveats on your example). On the other hand, your friend is correct that for built-in types, passing by reference should not result in any significant performance gains, and could even result in marginal performance losses. I come from a C background, so I tend to think of references in terms of pointers (even though there are some subtle differences), and a "char*" will be bigger than a "char" on any platform with which I'm familiar.
[EDIT: removed incorrect information.]
The bottom line, in my opinion, is that when you're passing larger user-defined types, and the called function only needs to read values without modifying them, passing by "type const&" is a good practice. As you say, it's self-documenting, and helps clarify the roles of the various pieces of your internal API.
Related
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.
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.
Hey there,
I wonder if it's worth passing primitive single values like int, float, double or char by pointer? Probably it's not worth!? But if you would simply pass everything by pointer, is this making the program slower?
Should you always just pass arrays as pointer?
Thanks!
I wonder if it's worth passing primitive single values like int, float, double or char by pointer?
What are you trying to accomplish? Do you want to be able to write to the passed in value? Or do you just need to use it? If you want to write to it, the idiomatic way is to pass by reference. If you don't need to write to it, you're best avoiding any risk that you'll write to it accidentally and pass by value. Pass by value will make a copy of the variable for local use. (as an aside, if you don't want to make a copy AND want some level of safety, you can pass by const reference)
But if you would simply pass everything by pointer, is this making the program slower?
Difficult to say. Depends on a lot of things. In both pass by value and pass by reference (or pointer) your making a new primitive type. In pass by value, you're making a copy. In pass by reference/pointer you're passing an address to the original. In the latter case, however, you're requiring an extra fetch of memory that may or may not be cached. Its very difficult to say 100% without measuring it.
That all being said, I doubt the difference is even noticeable. The compiler may be able to optimize out the copy in many pass-by-value cases, as indicated in this article. (thanks Space C0wb0y).
Should you always just pass arrays as pointer?
From this.
In C++ it is not possible to pass a complete block of memory by value as a parameter to a function, but we are allowed to pass its address.
To pass an array:
int foo(int bar[], unsigned int length)
{
// do stuff with bar but don't go past length
}
I'd recommended avoiding arrays and using std::vector which has more easily understood copy semantics.
It's probably not worth passing primitive values by pointer if your concern is speed -- you then have the overhead of the "indirection" to access the value.
However, pointers often are the "width of the bus", meaning the processor can send the whole value at once, and not "shift" values to send-down-the-bus. So, it is possible pointers are transferred on the bus faster than smaller types (like char). That's why the old Cray computers used to make their char values 32 bits (the width of the bus at that time).
When dealing with large objects (such as classes or arrays) passing pointer is faster than copying the whole object onto the stack. This applies to OOP for example
Look in your favorite C++ textbook for a discussion of "output parameters".
Some advantages of using a pointer for output parameters instead of a reference are:
No surprising behavior, no action at a distance, the semantics are clear at the call site as well as the caller.
Compatibility with C (which your question title suggests is important)
Usable by other languages, functions exported from a shared library or DLL should not use C++-only features such as references.
You should rarely have to pass anything by pointer. If you need to modify the value of the parameter, or want to prevent a copy, pass by reference, otherwise pass by value.
Note that preventing a copy can also be done by copy-elision, so you have to be very careful not to fall into the trap of premature optimization. This can actually make your code slower.
There's is no real answer to your question except few rules that I tend to bare in mind:
char is 8 bytes and a pointer is 4 bytes so never pass a single char as a pointer.
after things like int and float are the same size as a pointer but a pointer has to be referenced so that technically takes more time
if we go to the pentium i386 assembler:
loading the value in a register of a parameter "a" in C which is an int:
movl 8(%ebp),%eax
the same thing but passed as a pointer:
movl 8(%ebp),%eax
movl (%eax),%eax
Having to dereference the pointer takes another memory operation so theorically (not sure it is in real life) passing pointers is longer...
After there's the memory issue. If you want to code effectively everything composed type (class,structure,arrays...) has to be passed by pointer.
Just imagine doing a recursive function with a type of 16bytes that is passed by copy for 1000 calls that makes 16000 bytes in the stack (you don't really want that do you ? :) )
So to make it short and clear: Look at the size of your type if it's bigger than a pointer pass it by pointer else pass it by copy...
Pass primitive types by value and objects as const references. Avoid pointers as much as you can. Dereferencing pointers have some overhead and it clutters code. Compare the two versions of the factorial function below:
// which version of factorial is shorter and easy to use?
int factorial_1 (int* number)
{
if ((*number) <= 1)
return 1;
int tmp = (*number) - 1;
return (*number) * factorial_1 (&tmp);
}
// Usage:
int r = 10;
factorial_1 (&r); // => 3628800
int factorial_2 (int number)
{
return (number <= 1) ? 1 : (number * factorial_2 (number - 1));
}
// Usage:
// No need for the temporary variable to hold the argument.
factorial_1 (10); // => 3628800
Debugging becomes hard, as you cannot say when and where the value of an object could change:
int a = 10;
// f cound modify a, you cannot guarantee g that a is still 10.
f (&a);
g (&a);
Prefer the vector class over arrays. It can grow and shrink as needed and keeps track of its size. The way vector elements are accessed is compatible with arrays:
int add_all (const std::vector<int>& vec)
{
size_t sz = vec.size ();
int sum = 0;
for (size_t i = 0; i < sz; ++i)
sum += vec[i];
}
NO, the only time you'd pass a non-const reference is if the function requires an output parameter.
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