Question
What T&& Means in C++11: Rvalue References Explained
Question
I have been exploring the new features introduced in C++11, and I noticed declarations such as T&& var.
What is this syntax called?
What does it mean exactly?
At first glance, it looks like a “double reference,” similar to how C-style code can use double pointers like T** var, but I am struggling to understand its purpose and when it would be used.
Short Answer
By the end of this page, you will understand that T&& in C++11 usually means an rvalue reference. You will learn what rvalues are, why rvalue references were added, how they enable move semantics and perfect forwarding, and how they differ from ordinary references like T& and const T&.
Concept
In C++11, T&& is called an rvalue reference.
To understand it, you first need to know that C++ expressions are often divided into two broad categories:
- lvalues: named objects that have a stable location in memory
- rvalues: temporary values, literals, or objects about to expire
For example:
int x = 10; // x is an lvalue
int y = x; // x is still an lvalue
int z = 5; // 5 is an rvalue
Before C++11, C++ had normal references like T& and const T&:
T&binds to modifiable lvaluesconst T&can bind to both lvalues and rvalues
C++11 added T&& so code can specifically bind to rvalues.
This matters because rvalues are often temporary objects that will not be used again. Since they are about to disappear, C++ can safely move their resources instead of copying them.
That is the main reason T&& exists:
- to support
Mental Model
Think of C++ objects like physical containers.
- An lvalue is a labeled storage box sitting on a shelf. It has a name and a location.
- An rvalue is a temporary package that just arrived and has not been put on a shelf.
A normal reference T& is like saying, “Give me access to that named box on the shelf.”
An rvalue reference T&& is like saying, “This temporary package is about to be discarded anyway, so I am allowed to take its contents instead of making a full copy.”
That is why T&& is so useful for performance. If the object is temporary, C++ can often reuse its internals rather than duplicate them.
Syntax and Examples
Basic syntax
T&& name = expression;
This usually means name is an rvalue reference, and expression must be an rvalue.
Simple example
int&& a = 5;
This works because 5 is an rvalue.
But this does not work:
int x = 5;
int&& a = x; // error: x is an lvalue
Even though x stores a value, the expression x itself is an lvalue because it has a name.
Using std::move
#include <iostream>
#include <string>
#include <utility>
{
std::string s1 = ;
std::string s2 = std::(s1);
std::cout << << s2 << ;
}
Step by Step Execution
Consider this example:
#include <iostream>
#include <utility>
#include <string>
void print(std::string& s) {
std::cout << "lvalue: " << s << '\n';
}
void print(std::string&& s) {
std::cout << "rvalue: " << s << '\n';
}
int main() {
std::string name = "Alice";
print(name);
print(std::string("Bob"));
print(std::move(name));
}
Step-by-step
-
std::string name = "Alice";- Creates a named string object.
nameis an lvalue.
-
print(name);
Real World Use Cases
Rvalue references appear in many real C++ programs.
1. Move constructors and move assignment
Classes that manage resources such as memory, file handles, sockets, or buffers often define move operations:
class Buffer {
public:
Buffer(Buffer&& other);
Buffer& operator=(Buffer&& other);
};
This allows efficient transfer of ownership instead of expensive copying.
2. Standard library containers
Containers such as std::vector use move semantics when growing or rearranging elements. This can make operations much faster for movable types.
3. Returning objects from functions
Functions often return objects by value:
std::string make_message() {
return "hello";
}
C++ can move the returned object efficiently when needed.
4. Perfect forwarding in generic code
Template utilities such as std::make_unique and emplace_back rely on T&& in a special template context to forward arguments efficiently.
5. Avoiding copies in APIs
Real Codebase Usage
In real projects, developers usually use T&& in a few important patterns.
Move constructors
class FileWrapper {
public:
FileWrapper(FileWrapper&& other) noexcept {
handle = other.handle;
other.handle = nullptr;
}
private:
void* handle = nullptr;
};
This pattern transfers ownership and leaves the source object in a valid but moved-from state.
Move assignment
class FileWrapper {
public:
FileWrapper& operator=(FileWrapper&& other) noexcept {
if (this != &other) {
handle = other.handle;
other.handle = nullptr;
}
return *this;
}
private:
void* handle = nullptr;
};
Overloads for performance
void set_value( std::string& s);
;
Common Mistakes
1. Thinking T&& means “reference to reference”
It does not mean the same thing as a double pointer like T**.
T&& is a language feature for rvalue references.
2. Assuming a named T&& variable is still an rvalue
This is one of the most common mistakes.
void f(std::string&& s) {
g(s); // s is an lvalue here because it has a name
}
If you want to pass it onward as an rvalue, use:
void f(std::string&& s) {
g(std::move(s));
}
3. Using std::move too early
std::string name = "Alice";
std::string other = std::move(name);
std::cout << name; // valid, but value is unspecified
A moved-from object is valid, but you should not assume it still contains its old value.
Comparisons
| Concept | Binds to lvalues? | Binds to rvalues? | Typical use |
|---|---|---|---|
T& | Yes | No | Modify a named object |
const T& | Yes | Yes | Read without copying |
T&& | No, not directly | Yes | Move from temporaries or expiring objects |
T& vs T&&
int x = 1;
int& a = x; // OK
int&& b = 2; // OK
int&& c = x;
Cheat Sheet
Quick definition
T&&usually means rvalue reference- Used for move semantics and perfect forwarding
Value categories
- lvalue: named object, stable identity
- rvalue: temporary value or expiring object
Binding rules
T& -> binds to non-const lvalues
const T& -> binds to lvalues and rvalues
T&& -> binds to rvalues
Examples
int x = 10;
int& a = x; // OK
const int& b = 5; // OK
int&& c = 5; // OK
int&& d = x; // Error
int&& e = std::move(x); // OK
Important rule
A named rvalue reference is an lvalue in expressions:
void {
(s);
(std::(s));
}
FAQ
What is T&& called in C++?
It is usually called an rvalue reference.
Is T&& a double reference?
No. It is not like a double pointer such as T**. It is a separate C++ language feature.
Why was T&& added to C++11?
It was added mainly to support move semantics and perfect forwarding, which improve performance and flexibility.
Can T&& bind to a normal variable?
Not directly. A named variable is usually an lvalue. You would need std::move(variable) to treat it as an rvalue.
What is the difference between const T& and T&&?
const T& can read from both lvalues and rvalues without copying. T&& is used when you want to move from or modify an expiring object.
Why is a named T&& parameter treated as an lvalue inside a function?
Because any named variable is an lvalue expression, regardless of its type.
What is std::move actually doing?
Mini Project
Description
Build a small class that manages a dynamic array and supports both copying and moving. This project demonstrates why rvalue references matter: copying duplicates data, while moving transfers ownership efficiently.
Goal
Create a resource-owning class with a move constructor and move assignment operator, then test the difference between copy and move behavior.
Requirements
- Create a class that allocates an array with
new[]and frees it in the destructor. - Add a copy constructor that performs a deep copy.
- Add a move constructor that transfers the pointer and resets the source object.
- Add a move assignment operator that safely transfers ownership.
- Write a
main()function that shows copy and move operations in action.
Keep learning
Related questions
Basic Rules and Idioms for Operator Overloading in C++
Learn the core rules, syntax, and common idioms for operator overloading in C++, including member vs non-member operators.
C++ Base Class Constructor Rules Explained
Learn how C++ base class constructors are called from derived classes, including order, syntax, defaults, and common mistakes.
C++ Casts Explained: C-Style Cast vs static_cast vs dynamic_cast
Learn the difference between C-style casts, static_cast, and dynamic_cast in C++ with clear examples, safety rules, and real usage tips.