I've been trying to understand rvalues, lvalues and references and their usage as a returning values of functions (methods) so i created few small examples for practice purpose.
So firstly, i came up with this code (after reading somewhere, possibly here, that whenever i have a "regular" (without reference) return value for some method, it is considered to be rvalue, exception is when i add reference operator sign in the return value, like in this example:
#include <iostream>
int x = 5;
int& References()
{
return x;
}
int main()
{
References() = 3;
std::cout << x;
getchar();
getchar();
}
So here, function References returns lvalue when called, and this code works out just fine, however, since this works, i thought that i can do something similar other way around, and this is what i tried:
#include <iostream>
int x = 5;
int References()
{
return x;
}
int main()
{
int a = References();
std::cout << a;
getchar();
getchar();
}
This code works just fine, the output is 5, which means that i successfully assigned value to the variable a, which is something i expected since this function returns "ordinary" integer so it a rvalue.
HOWEVER,
when i once again add reference operator sign to the return value of function References, again, it works fine:
#include <iostream>
int x = 5;
int& References()
{
return x;
}
int main()
{
int a = References();
std::cout << a;
getchar();
getchar();
}
So, even though my function now returns int& which is returned as lvalue, this code still works and the output is still 5, which means that i managed to assign the value to my variable a successfully. What is going on here? Any help appreciated!
When you return by reference you have an lvalue, when you return by value you have a prvalue. In your case the difference you can read from both of them, but cannot assign to prvalue, not clear where is your confusion coming from:
int i1 = lvalue; // fine
int i2 = prvalue; // fine
but:
lvalue = 123; // fine
prvalue = 123; // error
closer to your case:
int &func1();
int func2();
int i1 = func1(); // fine
int i2 = func2(); // fine
func1() = 123; // fine
func2() = 123; // error
more info: Value Category
When you use a reference in an expression or an assignment, it evaluates out to what the reference refers to, not the memory address, which I suppose is what you expect to see.
Compare the output of the following functions:
int x = 5;
int& Reference()
{
return x;
}
int *Pointer()
{
return &x;
}
int main()
{
std::cout << Reference() << std::endl;
std::cout << Pointer() << std::endl;
return 0;
}
According to https://learn.microsoft.com/en-us/previous-versions/f90831hc(v=vs.140) :
You can think of an lvalue as an object that has a name. All variables, including nonmodifiable (const) variables, are lvalues. An rvalue is a temporary value that does not persist beyond the expression that uses it.
The third example is exactly the same as the second one, it's copying the value. You can copy a value from an lvalue just how you can copy a value from an rvalue. If your a variable was of type int& instead, you wouldn't be copying the actual value, you'd just get the same reference. This might help you understand:
#include <iostream>
int x = 5;
int& References()
{
return x;
}
int main()
{
int a = References();
int& b = References();
std::cout << a; // 5
std::cout << b; // 5
std::cout << x; // 5
a = 6;
b = 7;
std::cout << a; // 6
std::cout << b; // 7
std::cout << b; // 7
getchar();
getchar();
}
For comparison:
int n = 10;
int& r = n;
int* p = &n;
int x = n; // copy by value
int y = r; // copy by value, too, use the variable referenced as source
int z = *p; // copy by value third time, using variable pointed to
int& r0 = r; // copy the reference, i. e. r0 now references n as well
int* p0 = p; // copy the pointer...
n = 12;
// now x, y, z all STILL have value 10!
// r, r0, *p and *p0, in contrast, all yield 12
Not different with functions:
int& ref() { return n; }
int val() { return n; }
int& r1 = ref(); // copy the reference, again r1 references n!
int& r2 = val(); // INVALID!!!
// the latter is comparable to:
int& r3 = 7; // invalid...
Related
Given the code sample below;
#include<iostream>
using namespace std;
int main(){
int a = 4;
const int &b = a;
const int &c = a * 2;
a = 10;
cout << b << endl;
cout << c << endl;
return 0;
}
When I run this, the output is
10
8
Why is C++ designed to behave differently when assigning l-value and r-value to const references?
The expression:
const int &c = a * 2;
Does NOT bind the resulting reference c to a. Instead it binds it to the rvalue that is the result of the expression a * 2, which is a temporary object that no longer has anything to do with a - thus changing a does not affect it.
This is as opposed to b, which is a reference to the object a.
const int &b = a;
const int &c = a * 2;
The b here is a reference (an alias) for a; as a changes value, b will reflect that.
c binds to the temporary object as calculated by the expression a * 2, as a changes value after the computation, the calculation is not recomputed, the value of c remains as it was originally computed.
Other answers already explain why you get the output that you get. However, lets assume you want
const int &c = a * 2;
a = 10;
cout << c << endl;
to print 20. This is possible, but not by using a const ref directly, e.g. like this:
struct myref {
const int& x;
myref(int& x) : x(x) {}
operator int() { return x*2;}
};
int main() {
int a = 0;
myref c(a);
a = 10;
std::cout << c << std::endl;
}
However, I would strongly suggest you not to use this code and I just wanted to demonstrate that it is possible (I took the "this is too ambitious" in a comment as a challenge).
I guess with lambdas this can be done in a much more elegant way, unfortunately I am not so familar with them.
I have some questions regarding this program:
#include <iostream>
#include <type_traits>
#include <functional>
using namespace std;
template <typename T> void foo ( T x )
{
auto r=ref(x);
cout<<boolalpha;
cout<<is_same<T&,decltype(r)>::value;
}
int main()
{
int x=5;
foo (x);
return 0;
}
The output is:
false
I want to know, if std::ref doesn't return the reference of an object, then what does it do? Basically, what is the difference between:
T x;
auto r = ref(x);
and
T x;
T &y = x;
Also, I want to know why does this difference exist? Why do we need std::ref or std::reference_wrapper when we have references (i.e. T&)?
Well ref constructs an object of the appropriate reference_wrapper type to hold a reference to an object. Which means when you apply:
auto r = ref(x);
This returns a reference_wrapper and not a direct reference to x (ie T&). This reference_wrapper (ie r) instead holds T&.
A reference_wrapper is very useful when you want to emulate a reference of an object which can be copied (it is both copy-constructible and copy-assignable).
In C++, once you create a reference (say y) to an object (say x), then y and x share the same base address. Furthermore, y cannot refer to any other object. Also you cannot create an array of references ie code like this will throw an error:
#include <iostream>
using namespace std;
int main()
{
int x=5, y=7, z=8;
int& arr[] {x,y,z}; // error: declaration of 'arr' as array of references
return 0;
}
However this is legal:
#include <iostream>
#include <functional> // for reference_wrapper
using namespace std;
int main()
{
int x=5, y=7, z=8;
reference_wrapper<int> arr[] {x,y,z};
for (auto a: arr)
cout << a << " ";
return 0;
}
/* OUTPUT:
5 7 8
*/
Talking about your problem with cout << is_same<T&,decltype(r)>::value;, the solution is:
cout << is_same<T&,decltype(r.get())>::value; // will yield true
Let me show you a program:
#include <iostream>
#include <type_traits>
#include <functional>
using namespace std;
int main()
{
cout << boolalpha;
int x=5, y=7;
reference_wrapper<int> r=x; // or auto r = ref(x);
cout << is_same<int&, decltype(r.get())>::value << "\n";
cout << (&x==&r.get()) << "\n";
r=y;
cout << (&y==&r.get()) << "\n";
r.get()=70;
cout << y;
return 0;
}
/* Ouput:
true
true
true
70
*/
See here we get to know three things:
A reference_wrapper object (here r) can be used to create an array of references which was not possible with T&.
r actually acts like a real reference (see how r.get()=70 changed the value of y).
r is not same as T& but r.get() is. This means that r holds T& ie as its name suggests is a wrapper around a reference T&.
I hope this answer is more than enough to explain your doubts.
std::reference_wrapper is recognized by standard facilities to be able to pass objects by reference in pass-by-value contexts.
For example, std::bind can take in the std::ref() to something, transmit it by value, and unpacks it back into a reference later on.
void print(int i) {
std::cout << i << '\n';
}
int main() {
int i = 10;
auto f1 = std::bind(print, i);
auto f2 = std::bind(print, std::ref(i));
i = 20;
f1();
f2();
}
This snippet outputs :
10
20
The value of i has been stored (taken by value) into f1 at the point it was initialized, but f2 has kept an std::reference_wrapper by value, and thus behaves like it took in an int&.
A reference (T& or T&&) is a special element in C++ language. It allows to manipulate an object by reference and has special use cases in the language. For example, you cannot create a standard container to hold references: vector<T&> is ill formed and generates a compilation error.
A std::reference_wrapper on the other hand is a C++ object able to hold a reference. As such, you can use it in standard containers.
std::ref is a standard function that returns a std::reference_wrapper on its argument. In the same idea, std::cref returns std::reference_wrapper to a const reference.
One interesting property of a std::reference_wrapper, is that it has an operator T& () const noexcept;. That means that even if it is a true object, it can be automatically converted to the reference that it is holding. So:
as it is a copy assignable object, it can be used in containers or in other cases where references are not allowed
thanks to its operator T& () const noexcept;, it can be used anywhere you could use a reference, because it will be automatically converted to it.
Added an example to show the difference in value you get when you pass the T& and ref(T) arguments in the bind function.
std::bind copies the argument provided unless it is passed by std::ref()/std::cref().
void f(int r1, int& r2, int w1, int& w2)
{
std::cout << r1 << r2 << w1 << w2; // 5 5 10 10
r1 = 9, r2 = 9, w1 = 9, w2 = 9;
}
int main()
{
int w1 = 5, w2 = 5, n1 = 5, n2 = 5;
int& r1 = n1;
int& r2 = n2;
std::function<void()> bound_f = std::bind(f, r1, r2, std::ref(w1), std::ref(w2));
r1 = 10, r2 = 10, w1 = 10, w2 = 10;
bound_f(); // 5 5 10 10
std::cout << r1 << r2 << w1 << w2; // 10 10 10 9
}
What's the difference in usage of function get1() and get2()?
struct x
{
float get1() const
{
float fx = 4;
fx += 1.5f;
return fx;
}
float& get2() const
{
float fx = 4;
fx += 1.5f;
return fx;
}
};
int main()
{
x t;
float x1 = t.get1();
float/*&*/ x2 = t.get2();
cout << x1 << endl;
cout << x2 << endl;
cin.get();
}
As i understand, get2() can only be const class member..
It's not clear for me completely. If someone can point me to a reference or just a short but complete solution, would be nice.
In your case, get2() invokes undefined behavior because you return a reference to a method-local that goes out of scope.
The difference is that returning float returns a float value, while float & returns a reference to a float. The reference can be used to alter the data of the referent; when returning by value you just get a copy.
It sounds like you are just confused about what references do, so here is the colloquial definition: a reference is another name for an object. That means that a reference requires the existence of its target to exist elsewhere, very similar to a (non-null) pointer.
Let me write a better example to illustrate the difference:
struct x
{
x() : data(0) { }
float get1() const
{
return data;
}
// Cannot be const now, because we can't return a non-const reference to what
// would be a const data member. (If this method were const then data would be a
// const float, and that cannot bind to float &.)
float & get2()
{
return data;
}
private:
float data;
};
Now we have two methods, one that returns data and one that returns a reference to it. The difference here is that with get2() you can actually change the value of x::data:
x an_x;
float a = an_x.get1(); // a is 0
a = 5; // a is 5, an_x.data is still 0
a = x.get1(); // a is 0 again, because an_x.data did not change
float & b = an_x.get2(); // b is 0
b = 5; // b is 5, and so is an_x.data!
a = x.get1(); // a is now 5, because an_x.data is 5
Notably, returning a reference makes the result of the expression an lvalue:
an_x.get1() = 5; // Compile-time error, because a float is not an lvalue.
an_x.get2() = 5; // Compiles, and sets an_x.data to 5.
This is a technique used by the standard library containers; vector<int> for example returns int & from its non-const operator[] overload, which is why some_vector[0] = 5; compiles and works as you would expect.
float fx = 4;
In your case fx is local variable. It will die once you come out of function. If you are returning float then you are making copy of value, so even fx die, no problem. But if you are returning float&, you are returning reference to died variable. Which is undefined behaviour.
Copying is costly operation. When you return reference, you are not making actual copy, but you are returning address of varaiable. You should return reference if your variable will alive after returning from function. But in your case, fx will die once you come out of function.
I simulated your case in below blocks of code, you can compare the output of two case for making clearly. Hope it help.
#include <iostream>
class A
{
public:
A()
{
std::cout << this << ": A()\n";
}
A(const A&)
{
std::cout << this << ": Copy constructor\n";
}
~A()
{
std::cout << this << ": ~A()\n";
}
};
struct x
{
A get1() const
{
A a;
return a;
}
A &get2() const
{
A a;
return a;
}
};
int main(int argc, char *argv[])
{
x t;
/*{
t.get1();
}*/
{
t.get2();
}
std::cin.get();
}
Please tell me the use of cascading, and when to use & before function like this int &func()
Where should i use that please give me small example, Thanks. I think it does return an address but no idea how to use.
You are about to commit a very common newbie mistake in C++, namely returning references to dead objects.
int &GetNumber()
{
int number = 123;
return number;
}
int main()
{
int x = GetNumber();
int y = x + 1;
}
Looks innocent but will create so-called undefined behaviour. This means that the program may do whatever it wants to - it will likely crash, or it will sometimes crash. In any case, it won't be safe. Your compiler may even warn you if you attempt to do this. The reason is that by the time GetNumber has finished, the local number is destroyed, and you end up with a reference to a destroyed object.
Usually, you will want to return a copy instead of a reference. This is the "normal" thing to do in C++:
int GetNumber() // now OK
{
int number = 123;
return number;
}
int main()
{
int x = GetNumber();
int y = x + 1;
}
Returning references is only safe when you know that the object referred to will continue to exist after the function returns. One example is when you are just returning a reference you were passed:
int &MyFunction(int &number)
{
// do something
return number;
}
This then allows you to chain functions:
struct Example
{
Example &MyFunction(Example &example)
{
// do something
return example;
}
};
int main()
{
Example example;
example.MyFunction(example).MyFunction(example).MyFunction(example);
}
Now, if this example strikes you as particularly useless (as it should), look at how the standard library handles << calls with std::ostream for a realistic use case.
std::cout << 1 << "a" << 0.5;
This syntax works because each operator<< call returns a reference to std::cout.
when to use &
Return by value vs return by reference
You usually return a reference when you want a caller to be able to change the original variable. Example can be returning elements of an array
struct Array
{
int values[ 10];
};
// Returns a reference to the nIndex element of rArray
int& Value( Array &rArray, int nIndex)
{
return Array.values[ nIndex];
}
int main()
{
Array myArray;
// Set the 10th element of sMyArray to the value 5
Value( myArray, 10) = 5;
assert( myArray.values[ 10] == 5); // OK
return 0;
}
Another example is returning reference to class member. You want to return original variable, not a copy of it. Consider:
struct A {
int something;
int f() { return something; }
int& g() { return something; }
};
int main()
{
A myA;
int i = myA.f(); // return by value: not original
// int but its copy with same value
i = 200;
assert( myA.something == 200); // fail
return 0;
}
but:
int main()
{
A myA;
int& i = myA.g(); // return by reference: original
// variable is referenced by i now
i = 200;
assert( myA.something == 200); // OK
return 0;
}
Operator chaining
Operator chaining is made to allow for expressions like:
a = b + c + d;
or
std::cout << "this" << " and " << "this";
Usually there is choice between returning by value or by reference made by considering the meaning of the operator or independent factors like for example that std::istream and std::ostream are not copyable, so trying to return objects of those types by value is an error.
Just a tiny question:
Can you tell me what's the issue here in this code ? It should print out 9 but it does 4.8921e-270, however, when uncommenting line 4, it works just fine, too.
I don't understand what might be wrong here. Thank you !
Code:
double& foo() {
double x = 9;
double &y = x;
//cout << y << "\n";
return y;
}
int main() {
cout << foo() << "\n";
}
Result:
4.8921e-270
It is a bad idea to return references/pointers to objects on the stack. They are likely destroyed when you leave the function. Try returning it as per value:
double foo() {
double x = 9;
double &y = x;
//cout << y << "\n";
return y;
}
Now the return value is copied instead of a reference to an object that is probably not existing anymore.
You are returning a reference to a local object, the object ceases to exist when foo completes, and then you get Undefined Behavior when you dereference it.
double foo() {
double x = 9;
double &y = x;
//cout << y << "\n";
return y;
}
Never a good idea to return references to objects on stack. Most likely they would be disappear when you leave the function. You might try returning it as per value.
You return a reference to a local variable - since the local variable goes out of scope as soon as foo() returns, the value no longer exists.
So you should either just change the return type to double (highly recommended) and return x or (if you absolutely want/have to return a reference) use a static variable instead:
double& foo() {
static double x = 9;
double &y = x;
return y;
}
I often return data members of a class by const ref:
class BigThing {...};
class Foo
{
public:
const BigThing & getBT() const { return bt; } // For constant BigThing.
BigThing & getBT() { return bt; } // For mutable BigThing.
private:
BigThing bt;
};
Then as long as your instance of Foo is in scope (you don't want to return a ref to a local variable) then using one of the getBT() should be safe and efficient.