Differencebetween a Const Reference and Normal Parameter

What is the difference between a const reference and normal parameter?

The difference is more prominent when you are passing a big struct/class:

struct MyData {
int a,b,c,d,e,f,g,h;
long array[1234];
};
void DoWork(MyData md);
void DoWork(const MyData& md);

When you use use 'normal' parameter, you pass the parameter by value and hence creating a copy of the parameter you pass. If you are using const reference, you pass it by reference and the original data is not copied.

In both cases, the original data cannot be modified from inside the function.


EDIT:

In certain cases, the original data might be able to get modified as pointed out by Charles Bailey in his answer.

Difference between reference and const reference as function parameter?

Without the error message, I'm not exactly sure what the compiler might be complaining about, but I can explain the reason logically:

In the line:

bar(foo()); 

The return value of foo() is a temporary A; it is created by the call to foo(), and then destructed as soon as bar() returns. Performing a non-const operation (i.e. an operation that changes the temporary A) doesn't make sense, as the object A is destructed right afterwards.

Looking a little more, this is a virtual dup of this question:

How come a non-const reference cannot bind to a temporary object?

which has an excellent answer.

Difference between const reference and reference

Given the overload set:

void setage(int&a) { std::cout << "&"; }
void setage(const int&a) { std::cout << "&c"; }

the first function is called only with variables that are non-const:

int a = 42;
setage(a); // prints &

The second function is called if you pass it a variable that is const, or if you pass it a literal value:

int const b = 42;
setage(b); // prints c&
setage(42); // prints c&

Note that if this overload set is written within a class, the same rules apply, and which function is called still depends on whether the passed in argument is a literal, non-const variable, or const variable.

C++ Difference Between Const Reference to Non Const Object and Non Const Reference to Non Const Object

"What is the purpose for the "const" keyword for a reference if the object it is referencing is not a const object?"
The purpose is to prevent that reference being used to modify the object it is referencing.

int i = 42; // non const object
const int &r1 = i; // const reference to non const object
r1 = 6 * 9; // error, r1 cannot be used to modify i;

Difference between C++ const references and consts?

For your particular example there's no difference.

And that means, no way to tell them apart, whatsoever.

However, since the first binds a reference to a temporary, when the type is of class type the temporary can be of a derived class, e.g. produced by a function! And it then has its destructor properly called at the end of the scope. This little el neato trick is used in ScopeGuard implementations (see the original ScopeGuard article in DDJ, by Petru Marginean and Andrei Alexandrescu -- Petru invented ScopeGuard and Andrei made a more general thing on top).

I once asked Bjarne Stroustrup, who created the C++ language, why the syntax in your first declaration is supported.

And his reply was that it was mostly to have uniform rules (i.e. to not make any special exception for local references as opposed to references as formal parameters). I think at that time neither of us were familiar with ScopeGuard. It's simple in retrospect, but it takes a mind like Petru's, or Andrei's, to come up with something like that! :-)

Cheers & hth.

C++: const reference, before vs after type-specifier

No difference as const is read right-to-left with respect to the &, so both represent a reference to an immutable Fred instance.

Fred& const would mean the reference itself is immutable, which is redundant; when dealing with const pointers both Fred const* and Fred* const are valid but different.

It's a matter of style, but I prefer using const as a suffix since it can be applied consistently including const member functions.

C++11 rvalue reference vs const reference

std::move doesn't actually move anything out of it's own. It's just a fancy name for a cast to a T&&. Calling test like this test(std::move(x)); only shows that a T&& is implicitly convertible to a const T&. The compiler sees that test only accepts const T& so it converts the T&& returned from std::move to a const T&, that's all there is to it.

const parameter vs const reference parameter

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”

Difference between returning a const reference and rvalue reference

A const lvalue reference can bind to anything. An rvalue reference can only bind to non-const rvalues.

            non-const lvalue   const lvalue   non-const rvalue   const rvalue
const T& yes yes yes yes
T&& no no yes no

As you can see, they are very different.

In addition, if a function call returns an lvalue reference, that expression is an lvalue, but if a function call returns an rvalue reference to object, that expression is an xvalue.

A function call is an lvalue if the result type is an lvalue reference type or an rvalue reference to function type, an xvalue if the result type is an rvalue reference to object type, and a prvalue otherwise.

As for when you would want to modify an rvalue - well this is precisely what move semantics are all about. Consider the following function call:

void func(std::string);

func(std::string("Hello"));

The expression std::string("Hello") is an rvalue that creates a temporary object. When initializing the std::string parameter with this rvalue, it will choose the constructor that takes an rvalue reference - the move constructor. This constructor then steals things from the rvalue, which is typically much faster than doing a full copy. We can steal from it because we know it's temporary.

As for when you should return const lvalue references or rvalue references:

  • Returning a const lvalue reference is most commonly used when you want to give access to read an "internal" object (perhaps a member of a class), but not allow people to modify it.

  • Returning an rvalue reference is most commonly used (not common at all) when you want to allow calling code to move from an "internal" object (perhaps a member of a class). So instead of moving from a temporary returned object (as they would when returning by value), they literally move from the internal object.

    This could also be achieved with a non-const lvalue reference, but then they would have to explicitly std::move it.

So it's not very likely that you'll need to return an rvalue reference.

Not that std::forward has a return type that looks like T&&. However, this is deceptive, because it may or may not be an rvalue reference depending on the type of T. See universal references.



Related Topics



Leave a reply



Submit