Lvalue#
An lvalue refers to an object with a clear location in memory that can be addressed. In other words, an lvalue is an expression that can appear on the left side of an assignment operator. For example, variables, array elements, dereferenced pointers, etc., are all lvalues.
Characteristics:
- Addressable: The result of an lvalue expression is an object that can be obtained by using the address operator
&
. - Persistence: Objects represented by lvalues continue to exist after the evaluation of the expression until they go out of scope or are explicitly destroyed.
Example:
int x = 10;
int *p = &x;
*p = 20;
Rvalue#
An rvalue refers to temporary objects created during the evaluation of an expression, usually without a clear memory location and cannot be addressed. Rvalues are typically constants, temporary objects, or return values.
Characteristics:
- Not Addressable: Rvalues do not have a fixed memory location, so they cannot be addressed.
- Transient: Objects represented by rvalues cease to exist after the evaluation of the expression.
Example:
int y = 5 + 3;
int z = y * 2;
Introduction to Rvalue Reference#
C++11 introduced rvalue references to more efficiently handle rvalues. Rvalue references are declared using &&
. They allow for capturing and manipulating rvalues in a more efficient manner, reducing unnecessary copying and moving operations.
Applications of Rvalue References:
- Move Semantics: By using move constructors and move assignment operators, ownership of resources can be transferred rather than copied.
- Perfect Forwarding: Using rvalue references and
std::forward
in template functions enables perfect forwarding of parameters.
Example:
class A {
public:
A() { std::cout << "Constructor" << std::endl; }
A(const A&) { std::cout << "Copy Constructor" << std::endl; }
A(A&&) { std::cout << "Move Constructor" << std::endl; }
};
void foo(A&& a) {
A b = std::move(a); // Move constructor is called
}
int main() {
A a;
foo(std::move(a)); // Convert a to an rvalue reference
return 0;
}
std::move(a)
converts the lvalue a
into an rvalue reference, thereby invoking the move constructor of A
instead of the copy constructor, reducing unnecessary copies and improving efficiency.