confusion about a function returning int&& - c++

I wrote some test code.
int getInt() {
int a = 3;
return a;
}
int& getIntR() {
int a = 3;
return a;
}
int getRL() {
return int(1);
}
int&& getRRL() {
return getRL();
}
int main() {
// works, even though there may cause some problem
int& d = getIntR();
// right,reference to a temporary variable
int&& e = getInt();
// right,because the returned value is lvalue which can't be assigned to rvalue referecen
//int&& f = getIntR();
// here is the code which confused me
int& g = getRRL();
int&& ee = 10;
int& e = ee;
}
I construct a function returns a int&& type, so I need a temporatory variable.
as getRRL() show, I think the code maybe treated like this.
int&& temp = 1;
int&g = temp;
temp is a reference to rvalue, but it itself is a lvalue, so i can assign this to int&, but the conpiler says "the initial value of of a non-const refernce must be lvalue" which means the returned type is not lvalue.
But the code below works well.
int&& ee = 10;
int& e = ee;
Can someone tell me the reason? Thanks very much!

Related

Difference between `int* const& x` and `int* const x` in C++

I've read of the differences between passing by value, passing by reference, and passing (a pointer) by constant reference, yet I'm don't understand the difference between the latter, and just passing a constant pointer. As an example, what is the difference between
int PI = 3;
int* getArg(int* const& x){
x = Π
return x;
}
int main() {
}
and
int PI = 3;
int* getArg(int* const x){
x = Π
return x;
}
int main() {
}
Both of these cause the same error: assignment of read-only parameter 'x'.
If you're clear on passing variables by value and by reference, then try breaking down complex types into parts to help make sense of what's going on:
using PointerToInt = int*;
using ConstPointerToInt = PointerToInt const;
int* getArg_v1(ConstPointerToInt x) {
x = Π // it's const by value so you're not allowed to change it
return x;
}
int* getArg_v2(ConstPointerToInt& x) {
x = Π // it's const by reference so you're not allowed to change it
return x;
}

Why is a reference type an lvalue when accessed with a temporary object?

Why does assigning a value to a reference variable being accessed using a temporary object work, but not for a non-reference type?
class a
{
public:
int m;
int &n;
a():m(2),n(m)
{
cout<< "A's constructor"<<endl;
}
};
int main()
{
// a().m = 6; // this gives an error that a temporary object is being used
// as an lvalue
a().n = 20; // But this line works
return 0;
}
But is a().n truely a temporary? Consider this code:
class a
{
public:
int m;
int &n;
a():m(2),n(m)
{
cout<< "A's constructor"<<endl;
}
a(int& _n):m(2),n(_n)
{
cout<< "A's constructor"<<endl;
}
};
int main()
{
a().n = 20; // (1)
int n = 0;
a(n).n // (2)
return 0;
}
The line (2) clearly shows that .n is not a temporary. It must not be, since it's a reference to the local n variable.
But then, the compiler cannot know what n will refer. One could even do n(rand_bool() ? m : _n) and it must work.
The compile instead uses the type system to know what should be assigned or not.
For example, the literal 9 is a pr-value of type int. You can't assign to it:
9 = 8; // nope
In your code, a() is a prvalue or type a. All of its value member also are. This is why a().m won't work. m is a prvalue.
But, a().n is an lvalue because n is a lvalue reference. No matter to which variable it points to.
a().n = 20;
works since n is a lvalue reference type. The compiler does not know that n is a reference to m in the implementation. It assumes that n is a valid lvalue reference and hence accepts that line.
In theory, when you assign to a().n, you could be assigning to a variable that lives independent of the life of a(). The compiler has no way of assessing that and will be in the way of the programmer if it didn't accept that line. Imagine the use case below:
// Global variable.
int gv;
class a
{
public:
int m;
int &n;
a():m(2), n(gv) // n is a reference to the global variable.
{
cout<< "A's constructor"<<endl;
}
};
int main()
{
a().n = 20; // Changes gv. It is a valid operation.
return 0;
}

Warning: returning reference to temporary - strange case (Clarification for Rvalue)

In this code:
const int & fun(const int &i)
{
return 2*i;
}
int main()
{
const int k=3;
cout<<fun(k)<<endl;
return 0;
}
In this case the parameters of fun are not local (No Temporary object made to store the Reference return type) then why this warning?
+ If I remove const from the return type of function fun it says
error: invalid initialization of non-const reference of type ‘int&’ from an rvalue of type ‘int’
But on removing 2* (only i left as value being returned) it doesn't show any error -> What I can think is this 2* thing is converting the return into Rvalue but then isn't the return value an Rvalue itself? Where am I going wrong?
return 2*i; does not multiply 2 by i and store that result into i. It multiples 2 by i and puts that result into a temporary. Trying to return that temporary by reference is a no go as it is destroyed at the end of that line. lifetime extension does not apply here.
If you want to modify i and return it you need to use operator *= which will modify i and give you a reference to it that you can return like
return i *= 2;
But fun would need to take a int& instead of const int &.
If you want to return an rvalue then what you do is return by value like:
int fun(const int &i)
{
return 2*i;
}
and now you can capture it like:
int main()
{
const int& ret = fun(3);
cout << ret << endl;
return 0;
}

Reference to pointer and malloc

Consider
int *p;
auto & pp = p;
pp = (decltype(pp))malloc(sizeof(decltype(*pp))); //line1
pp = (decltype(p))malloc(sizeof(decltype(*p))); //line2
why line1 is not acceptible but line2 is fine suggesting they are of different types.
Why pp and p are not of same type?
pp is a reference to an int *
According to https://msdn.microsoft.com/en-us/library/dd293667.aspx
"The following code fragment initializes variable x to type int, variable y to a reference to type const int, and variable fp to a pointer to a function that returns type int."
C++
int f(int x) { return x; }
int main()
{
auto x = f(0);
const auto & y = f(1);
int (*p)(int x);
p = f;
auto fp = p;
//...
}

passing const pointer by reference

I am confused that why following code is not able to compile
int foo(const float* &a) {
return 0;
}
int main() {
float* a;
foo(a);
return 0;
}
Compiler give error as:
error: invalid initialization of reference of type 'const float*&' from expression of type 'float*'
but when I try to pass without by reference in foo, it is compiling fine.
I think it should show same behavior whether I pass by reference or not.
Thanks,
Because it isn't type-safe. Consider:
const float f = 2.0;
int foo(const float* &a) {
a = &f;
return 0;
}
int main() {
float* a;
foo(a);
*a = 7.0;
return 0;
}
Any non-const reference or pointer must necessarily be invariant in the pointed-to type, because a non-const pointer or reference supports reading (a covariant operation) and also writing (a contravariant operation).
const must be added from the greatest indirection level first. This would work:
int foo(float* const &a) {
return 0;
}
int main() {
float* a;
foo(a);
return 0;
}