What are lvalues/rvalues/xvalues/etc?
An lvalue (whose name derives from "left value") is a function or object. It "has identity" and "cannot be moved from". After an expression is complete, does your value persist? Can you reference it? If yes, it is an lvalue. If no, probably not. For example, a function "foo" is an lvalue. A variable "x" is an lvalue. The expression "1+1" is not an lvalue. Additionally, an expression may evaluate to an lvalue, like the following: (true ? x : y). As a rule of thumb, ask yourself: "Can I take the address of this value? If yes, it is probably an lvalue."
An rvalue (whose name derives from "right value") is a temporary object or value which is not associated with an object. If it's not an lvalue, but it is a value, it's probably an rvalue. For example, "x+1" is an rvalue. "foo()" is also an rvalue.
C++ 11 has introduced a new concept to the language known as rvalue reference. If you are familiar with the "pass by reference" syntax (&), this is similar: "&&". For example,
String s = "abc";
getLvalue() { return s; }
getRvalue() { return "abc"; }
doPrint(const String& str) {
std::cout << "String passed by reference: " << str;
}
doPrint(String&& str) {
std::cout << "String passed by rvalue reference: " << str;
}
doPrint(getLvalue());
doPrint(getRvalue());
From this code, we should see that the first string is passed by reference, as it is an lvalue, but the second is passed by "rvalue reference" -- it references a temporary object. Not a variable, not a function: a temporary object.
The last bit of knowledge we need is understanding xvalues. An xvalue, or expiring value, refers to an object, near the end of its lifetime, which can be moved. Xvalues can be generated from rvalue references in certain situations.
Let's revisit our example above.
std::string str = "hello";
std::cout << std::move(str);
C++ 11 has introduced a new concept to the language known as rvalue reference. If you are familiar with the "pass by reference" syntax (&), this is similar: "&&". For example,
String s = "abc";
getLvalue() { return s; }
getRvalue() { return "abc"; }
doPrint(const String& str) {
std::cout << "String passed by reference: " << str;
}
doPrint(String&& str) {
std::cout << "String passed by rvalue reference: " << str;
}
doPrint(getLvalue());
doPrint(getRvalue());
From this code, we should see that the first string is passed by reference, as it is an lvalue, but the second is passed by "rvalue reference" -- it references a temporary object. Not a variable, not a function: a temporary object.
The last bit of knowledge we need is understanding xvalues. An xvalue, or expiring value, refers to an object, near the end of its lifetime, which can be moved. Xvalues can be generated from rvalue references in certain situations.
Let's revisit our example above.
std::string str = "hello";
std::cout << std::move(str);
In particular, std::move produces an xvalue expression that identifies its argument t. It is exactly equivalent to a static_cast to an rvalue reference type.
In this example, str is an lvalue in the first line, and str is in rvalue in the second line. When we call std::move(str), we reference the rvalue str, and create a reference to it,
Comments
Post a Comment