Code:
void test(int&& a)
{
a++;
std::cout << a << std::endl;
}
and execute:
test(0);
why output 1? Cause I think 0 is rvalue, it could not be changed.
If you bind a non-class, non-array prvalue, such as a numeric literal, to a reference, the reference will actually be bound to a temporary variable which is a copy of the original value. That is,
int&& a = 0;
creates a temporary int object with the value zero, and then binds a to that.
When you call test(0), the same rule applies, and the reference parameter is bound to a temporary; the temporary is incremented and you get the result 1. Of course you are not incrementing 0 itself.
Both rvalue references and lvalue references to const can bind to a temporary. The difference is, the former is modifiable, the latter is not.
int& i = 0; // invalid
const int& i = 0; // valid
++i; // invalid
int&& i = 0; //valid
++i; // valid;
Related
Recently I was studying lvalue and rvalue concept.
When I do
int&z = 0 ;
I get an expected error like :
initial value of reference to non-const must be an lvalue
However, when I do this with a function that returns lvalue reference like:
int& get_value(){
static int x = 10;
return x;
}
//This line turns out to be valid...
get_value() = 20;
I wonder why get_value() = 20; is valid.
The error message makes it quite clear:
initial value of reference to non-const must be an lvalue
(emphasis mine). So long as the reference is initially bound to an l-value, everything is fine (so long as you don't use a reference to a stack local variable, of course). The reference returned from get_value is bound to x which is an l-value, and that's allowed.
Without the function, you are essentially writing:
int x = 10; // x is an l-value
int &get_x = x; // just a variable instead of a function
get_x = 20; // assignment is ok
which is clearly ok.
Consider the following code -
#include <iostream>
#include <stdio.h>
const int & retRef() {
return 6;
}
int main()
{
const int& k = retRef();
printf("Value: %d\n", k);
printf("Address: %p\n", &k);
printf("Value: %d\n", k);
return 0;
}
The output is -
Value: 6
Address: 0x7ffd45bf544c
Value: 32692
Why the value changed after printing the address of the variable k? If I replace the line const int& k = retRef() with const int& k = 6;, the output is as expected.
Why is this different behavior? Thanks in advance
Your code has undefined behavior; You're trying to bind a temporary int (which is constructed from literal 6) to reference as return value, but the temporary will be destroyed immediately then retRef() always returns a dangled reference, and k is dangled too. Any dereference on it leads to UB.
Whenever a reference is bound to a temporary or to a subobject thereof, the lifetime of the temporary is extended to match the lifetime of the reference, with the following exceptions:
a temporary bound to a return value of a function in a return statement is not extended: it is destroyed immediately at the end of the return expression. Such function always returns a dangling reference.
On the other hand, const int& k = 6; works fine because the lifetime of temporary is extended to the lifetime of k as stated above.
You are returning a reference to a temporary object which will cause undefined behaviour. The object will not be available once function returns.
n4659 - § 15.2:
(6.2) — The lifetime of a temporary bound to the returned value in a function return statement (9.6.3) is not extended; the temporary is destroyed at the end of the full-expression in the return statement.
In function retRef you are returning a reference to a local variable.
The objects inside the function will be destroyed when exiting the function and all references to it will become invalid. Using of that link will further entail undefined behavior...
const int & retRef()
{
return 6;
}
I'm new to C++. I'm trying to learn the concept of const. Could someone please tell me why the first statement is illegal while the second is legal?
int i = -1, &r = 0;
const int i = -1, &r = 0;
i is a red herring here, the issues are int &r = 0; vs. const int &r = 0;
A non-const lvalue reference must bind directly to an lvalue. 0 is not an lvalue, so int &r = 0; fails.
A const lvalue reference may be bound to an rvalue. When this happens, it is not bound directly. Instead, a temporary (of type const int here) is created and copy-initialized from the rvalue. The temporary has its lifetime extended by virtue of this binding.
So const int &r = 0; is legal and has a similar effect to const int __temp = 0; const int &r = __temp;
int i = -1, &r = 0; is same as:
int i = -1;
int &r = 0;
The problem here is you can't write int &r = 0;, because initialization of a reference need the initializer to be an lvalue (an object whose address
you can take), while the literal 0 is not.
But the initializer of a const reference need not to be an lvalue, so const int &r = 0; is fine.
The i = -1, bit creates an i variable initialised to -1, but makes no difference to the references that come after, so let's focus on:
int &r = 0; // illegal
const int &r = 0;
What the const int& version does is extend the lifetime of the value it's bound to: in other words, the 0 value is kept around for use via r, until the end of the scope in which r is defined.
It's easy to point out that the same generosity is not extended to the int& version "because it's not an lvalue". The more interesting question of why is discussed in the C++ FAQ:
In C++, non-const references can bind to lvalues and const references can bind to lvalues or rvalues, but there is nothing that can bind to a non-const rvalue. That's to protect people from changing the values of temporaries that are destroyed before their new value can be used. For example:
void incr(int& a) { ++a; }
int i = 0;
incr(i); // i becomes 1
incr(0); // error: 0 is not an lvalue
If that incr(0) were allowed either some temporary that nobody ever saw would be incremented or - far worse - the value of 0 would become 1. The latter sounds silly, but there was actually a bug like that in early Fortran compilers that set aside a memory location to hold the value 0.
int i = -1, &r = 0; is basically equivalent to writing
int i = -1;
int &r = 0
The second statement tries to bind a non-const lvalue to 0, which is not an lvalue at all (0 is not an object whose address can be taken). However, it succeeds when it is a const lvalue as that be bound (not directly though) to an rvalue.
How come the following works?
double doubleVal(double val) {
return val*2;
}
int main()
{
double myVal = 3.0;
double(*&&ptr)(double) = &doubleVal; // Why?
}
I don't understand why the function address can be converted to an rvalue reference.. isn't it an lvalue?
Your code is basically asking why:
using T = ...;
T someVal;
T*&& ref = &someVal;
works. While someVal is an lvalue, &someVal is a prvalue, which is a kind of rvalue. Any rvalue may be used to initialize an rvalue reference.
The compiler recognizes the syntax as being a function pointer
double(*ptr)(double) = &doubleVal;
The additional && is applied against ptr, not the properties of the function to which ptr will point
double(*&&ptr)(double) = &doubleVal;
accepts a reference to an rvalue, and the thing on the right is an rvalue - it doesn't have a name or an address until it is stored in ptr.
return &(&doubleVal); // warning - returning address of temporary
#include<iostream.h>
int main()
{
int m = 2;
int &x = m++;
cout<<m;
return 0;
}
this code should gives
OUTPUT:
3
but this code gives error:
invalid initialization of non-const reference of type 'int&' from a temporary of type 'int'.
Post increment operator returns a temporary object with the value of m before increment.
Non const lvalue references can't be bound to temporary objects. Thus, the compiler rightfully complains.
m++ has to increase m (as a side effect), but evaluate to the original value. It does that by returning a temporary variable holding the value of m before increment.
An non-const l-value reference cannot bind to a temporary object.
You could write:
int &x = ++m;
This works because the pre–increment operator has to return the value after the increment, thus being able to evaluate to an l-value reference to m.
But I wouldn’t recommend that for clarity sake.
You can't use post increment to assign references - it is a temporary object
Here
int &x = m++;
you are assigning a temporary object (right side) to a reference(left side) which doesnt make any sense.
Instead,write:
int &x = ++m;