Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

const parameter vs const reference parameter

Implementation 1:

foo(const Bar x);

Implementation 2:

foo(const Bar & x);

If the object will not be changed within the function, why would you ever copy it(implementation 1).

Will this be automatically optimized by the compiler?

Summary: Even though the object is declared as const in the function declaration, it is still possible that the object be edited via some other alias &.

If you are the person writing the library and know that your functions don't do that or that the object is big enough to justify the dereferencing cost on every operation, than foo(const Bar & x); is the way to go.

Part 2:

Will this be automatically optimized by the compiler?

Since we established that they are not always equivalent, and the conditions for equivalence is non-trivial, it would generally be very hard for the compiler to ensure them, so almost certainly no

like image 507
aiao Avatar asked Dec 17 '12 16:12

aiao


3 Answers

you ask,

“If the object will not be changed within the function, why would you ever copy it(implementation 1).”

well there are some bizarre situations where an object passed by reference might be changed by other code, e.g.

namespace g { int x = 666; }

void bar( int ) { g::x = 0; }

int foo( int const& a ) { assert( a != 0 );  bar( a );  return 1000/a; }  // Oops

int main() { foo( g::x ); }

this has never happened to me though, since the mid 1990s.

so, this aliasing is a theoretical problem for the single argument of that type.

with two arguments of the same type it gets more of a real possibility. for example, an assignment operator might get passed the object that it's called on. when the argument is passed by value (as in the minimal form of the swap idiom) it's no problem, but if not then self-assignment generally needs to be avoided.

you further ask,

“Will this be automatically optimized by the compiler?”

no, not in general, for the above mentioned reason

the compiler can generally not guarantee that there will be no aliasing for a reference argument (one exception, though, is where the machine code of a call is inlined)

however, on the third hand, the language could conceivably have supported the compiler in this, e.g. by providing the programmer with a way to explicitly accept any such optimization, like, a way to say ”this code is safe to optimize by replacing pass by value with pass by reference, go ahead as you please, compiler”

like image 161
Cheers and hth. - Alf Avatar answered Nov 20 '22 21:11

Cheers and hth. - Alf


Indeed, in those circumstances you would normally use method 2.

Typically, you would only use method 1 if the object is tiny, so that it's cheaper to copy it once than to pay to access it repeatedly through a reference (which also incurs a cost). In TC++PL, Stroustrup develops a complex number class and passes it around by value for exactly this reason.

like image 5
NPE Avatar answered Nov 20 '22 19:11

NPE


It may be optimized in some circumstances, but there are plenty of things that can prevent it. The compiler can't avoid the copy if:

  • the copy constructor or destructor has side effects and the argument passed is not a temporary.
  • you take the address of x, or a reference to it, and pass it to some code that might be able to compare it against the address of the original.
  • the object might change while foo is running, for example because foo calls some other function that changes it. I'm not sure whether this is something you mean to rule out by saying "the object will not be changed within the function", but if not then it's in play.

You'd copy it if any of those things matters to your program:

  • if you want the side effects of copying, take a copy
  • if you want "your" object to have a different address from the user-supplied argument, take a copy
  • if you don't want to see changes made to the original during the running of your function, take a copy

You'd also copy it if you think a copy would be more efficient, which is generally assumed to be the case for "small" types like int. Iterators and predicates in standard algorithms are also taken by value.

Finally, if your code plans to copy the object anyway (including by assigning to an existing object) then a reasonable idiom is to take the copy as the parameter in the first place. Then move/swap from your parameter.

like image 2
Steve Jessop Avatar answered Nov 20 '22 20:11

Steve Jessop