What are the benefits to passing integral types by const ref
The question: Is there benefit to passing an integral type by const reference as opposed to simply by value.
ie.
void foo(const int& n); // case #1
vs
void foo(int n); // case #2
The answer is clear for user defined types, case #1 avoids nee开发者_开发知识库dless copying while ensuring the constness of the object. However in the above case, the reference and the integer (at least on my system) are the same size, so I can't imagine there being a whole lot of difference in terms of how long it takes for the function call (due to copying). However, my question is really related to the compiler inlining the function:
For very small inline functions, will the compiler have to make a copy of the integer in case #2? By letting the compiler know we won't change the reference can it inline the function call without needless copying of the integer?
Any advice is welcome.
Passing a built-in int type by const ref will actually be a minor de-optimization (generally). At least for a non-inline function. The compiler may have to actually pass a pointer that has to be de-referenced to get the value. You might think it could always optimize this away, but aliasing rules and the need to support separate compilation might force the compiler's hand.
However, for your secondary question:
For very small inline functions, will the compiler have to make a copy of the integer in case #2? By letting the compiler know we won't change the reference can it inline the function call without needless copying of the integer?
The compiler should be able to optimize away the copy or the dereference if semantics allow it, since in that situation the compiler has full knowledge of the state at the call site and the function implementation. It'll likely just load the value into a register have its way with it and just use the register for something else when it's done with the parameter. Of course,all this is very dependent on the actual implementation of the function.
I actually find it irritating when somebody uses const references like this for the basic datatypes. I can't see any benefit of doing this, although it may be argued that for datatypes bigger than sizeof(pointer)
it may be more efficient. Although, I really don't care about such minute 'optimizations'.
It depends on the compiler, but I'd expect that any reasonable optimizer would give you the same results either way.
I tested with gcc, and the results were indeed the same. here's the code I tested:
inline int foo(const int& n) {
return n * 2;
}
int bar(int x) {
int y = foo(x);
return y;
}
(with and without const & on foo's n parameter)
I then compiled with gcc 4.0.1 with the following command line:
g++ -O3 -S -o foo.s foo.cc
The outputs of the two compiles were identical.
It's usually not worth it. Even for inline function, the compiler won't be stupid. The only time I would say it's appropriate is if you had a template; it might not be worth the extra effort to specialize for builtins just to take a copy instead of a reference.
You can use boost::call_traits<your type>::param_type
for optimal parameter passing. Which defaults to simple parameter passing of primitive types and passing by const reference of structs and classes.
A lot of people are saying there's no difference between the two. I can see one (perhaps contrived) case in which the difference would matter...
int i = 0;
void f(const int &j)
{
i++;
if (j == 0)
{
// Do something.
}
}
void g()
{
f(i);
}
But.. As others have mentioned... integers and pointers are likely to be of similar size. For something as small as an integer, references will decrease your performance. It probably won't be too noticeable unless your method is called a lot, but it will be there. On the other hand, under some circumstances the compiler may optimize it out.
When writing or using templates, you may end up with (const int &) because the template writer can't know what the type actually is. If the object is heavyweight, passing a reference is the right thing to do; if it's an int or something, the compiler may be able to optimize it away.
In the absence of some kind of external requirement, there is generally no reason to do something like this for a one-off function -- it's just extra typing, plus throwing around references actually tends to inhibit optimization. Copying small data in registers is much cheaper than reloading it from memory in case it's changed!
I can't think of any benefit. I've even seen recommendation that when writing templates, you use meta-programming to pass integral types by value and only use const reference for non-integral types.
well the cost of a reference is the same typically of that of an integral type, but with the reference you have an indirection that has to take place, because the reference to some memory has to be resolved into a value.
Just copy by value, stick to an immutable convention for built-in types.
Don't do this. int
is the same size as pointer/reference on common 32-bit plattforms, and smaller on 64-bit, thus you could get yourself a performance disadvantage instead of a benefit. I mean, all function arguments are pushed onto stack in order so that a function can read them, and it will either be your int, or its address in the case of reference. Another disadvantage is that the callee will either access your n
through an indirection (dereferencing an address), or it will make copy on its stack as an optimization.
If you make some changes to an int passed by value, it might be written either back onto the place on the stack where it was passed, or onto a new stack position. The second case naturally isn't advantagous, but shouldn't happen. By consting you bar yourself from making such a change, but this would work the same with const int
.
In the proper inline case it doesn't matter, naturally, but keep in mind that not everything where you write inline, will be.
Please read Want Speed? Pass by Value by Dave Abrahams.
It's not only performance. A true story: this week I noticed that a colleague tried to improve upon the Numerical Recipes and replaced the macro
#define SHFT(a,b,c,d) do { (a)=(b); (b)=(c); (c)=(d); } while (0)
by this function
inline void Rotate(double& dFirst, double& dSecond, double& dThird, const double dNewValue)
{
dFirst = dSecond;
dSecond = dThird;
dThird = dNewValue;
} // Function Rotate
This would have worked, if he had passed the last parameter by reference, but as it is, this code
Rotate(dum,*fb,*fa,dum);
which was supposed to swap *fa and *fb no longer works. Passing it by reference without const is not possible, as in other places non-l-values are passed to the last parameter.
精彩评论