I've been carefully studying C++ catogories recently. The difference between lvalue and rvalue seems to be clear, but I got confused when it comes to prvalue and xvalue.
Given the example below:
#include <iostream>
using std::cout;
using std::endl;
using std::move;
class Type {
public:
int value;
Type(const int &value=0) :value(value) {}
Type(const Type &type) :value(type.value){}
Type(Type &&type) noexcept :value(type.value) {}
Type &operator= (const Type &type) {
value = type.value;
return *this;
}
Type &operator=(Type &&type) noexcept{
value = type.value;
return *this;
}
};
Type foo1(const Type &value) {
return Type(value);
}
Type &&foo2(const Type &value) {
return Type(value);
}
int main() {
Type bar1(123);
cout << foo1(bar1).value << endl;
cout << foo2(bar1).value << endl;
Type bar2;
bar2 = foo1(bar1);
cout << bar2.value << endl;
bar2 = foo2(bar1);
cout << bar2.value << endl;
return 0;
}
Running the example, the console puts:
123
123
123
-858993460
Can anyone explan why it gives an unexpected value in the last output?
What feature does this example show about xvalue?
foo2
is returning reference bound to temporary which is destroyed immediately; it always returns a dangled reference.
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.
Dereference on the returned reference like foo2(bar1).value
and bar2 = foo2(bar1);
leads to UB; anything is possible.
On the other hand, foo1
doesn't have such issue. The return value is moved from the temporary object.