C++ lvalue, rvalue, and rvalue references
Understanding lvalues, rvalues, and rvalue references is essential for mastering modern C++ features like move semantics and perfect forwarding.
π What is an lvalue?
An lvalue refers to a location in memory β it has a name and can appear on the left-hand side of an assignment.
int x = 10;
x = 20; // x is an lvalue
int* p = &x; // can take address of x
π What is an rvalue?
An rvalue is a temporary object or value that does not have a persistent memory address. It typically appears on the right-hand side of assignments.
int x = 10;
int y = x + 5; // x + 5 is an rvalue
y = 100; // 100 is an rvalue
You cannot take the address of an rvalue, and it usually lives only for the duration of the expression.
π Rvalue references
C++11 introduced rvalue references using the `&&` syntax. This allows binding to rvalues and enables move semantics.
void process(int& x); // lvalue reference
void process(int&& x); // rvalue reference
int main() {
int a = 42;
process(a); // calls int&
process(10); // calls int&&
}
Rvalue references are commonly used in move constructors, move assignment operators, and with `std::move`.
π lvalue vs rvalue Comparison
| Feature | lvalue | rvalue |
|---|---|---|
| Has a name | Yes | Usually no |
| Can take address | Yes | No |
| Assignable (on left of =) | Yes | No |
| Lifetime | Scope-based | Temporary |
Bindable to && |
No | Yes |
π§ͺ std::move and move semantics
std::string a = "hello";
std::string b = std::move(a); // a is "moved" into b
`std::move` doesnβt actually move anything β it simply casts an lvalue to an rvalue, enabling the move constructor or move assignment to take over.
π‘ When to use
- Use lvalue references (
&) when:- You want to read/write an existing named object
- You donβt want to transfer ownership or modify resource ownership
- Use rvalue references (
&&) when:- You want to βstealβ resources from a temporary
- Implementing move constructors or move assignment
- You want to optimize performance by avoiding deep copies
Summary
lvalues and rvalues are the building blocks of C++ expressions. Rvalue references unlock the power of move semantics and are vital for writing high-performance C++ code. Knowing how and when to use them is a core skill for modern C++ developers.
C/C++ Programming
- Understanding std::transform_reduce in Modern C++
- Implement a Lock Acquire and Release in C++
- Detecting Compile-time vs Runtime in C++: if consteval vs std::is_constant_evaluated()
- C++ Forward References: The Key to Perfect Forwarding
- Understanding dynamic_cast in C++: Safe Downcasting Explained
- C vs C++: Understanding the restrict Keyword and its Role in Optimization
- C++ Lvalue, Rvalue and Rvalue References
- C++ assert vs static_assert
- Why auto_ptr is Deprecated in C++?
- C++ What is the consteval? How is it different to const and constexpr?
- Tutorial on C++ std::move (Transfer Ownership)
- const vs constexpr in C++
- Tutorial on C++ Ranges
- Tutorial on C++ Smart Pointers
- Tutorial on C++ Future, Async and Promise
- The Memory Manager in C/C++: Heap vs Stack
- The String Memory Comparision Function memcmp() in C/C++
- Modern C++ Language Features
- Comparisions of push_back() and emplace_back() in C++ std::vector
- C++ Coding Reference: is_sorted_until() and is_sorted()
- C++ Coding Reference: iota() Setting Incrementing Values to Arrays or Vectors
- C++ Coding Reference: next_permutation() and prev_permutation()
- C++ Coding Reference: count() and count_if()
- C++ Code Reference: std::accumulate() and Examples
- C++ Coding Reference: sort() and stable_sort()
- The Next Permutation Algorithm in C++ std::next_permutation()
βEOF (The Ultimate Computing & Technology Blog) β
Last Post: C++ assert vs static_assert
Next Post: ROS Topics, Services, and Actions Explained with Clear Examples