A reference is another name for an existing object. C++ has lvalue references (T&), const references (const T&) and rvalue references (T&&).
lvalue references
#include <iostream>
#include <vector>
int main() {
int x = 1;
int& r = x; // r is x
r = 5;
std::cout << x << ' ' << (&r == &x) << '\n';
int y = 99;
r = y; // NOT re-binding: assigns 99 to x
std::cout << x << '\n';
std::vector<int> v{1, 2, 3};
int& first = v[0]; // reference to an element
first = 100;
std::cout << v[0] << '\n';
}5 1
99
100Must be initialised:
int& r;is an error.Can't be null and can't be re-seated to another object.
No “reference to reference”, no arrays of references, no pointers to references.
const references bind to temporaries
#include <iostream>
#include <string>
std::string makeName() { return "temp"; }
int main() {
const std::string& ref = makeName(); // lifetime of the temporary is extended to ref's scope
const int& n = 42; // binds to a materialised temporary
std::cout << ref << ' ' << n << '\n';
// std::string& bad = makeName(); // error: non-const lvalue ref can't bind to an rvalue
}temp 42lvalues and rvalues
#include <iostream>
#include <string>
#include <utility>
void take(const std::string&) { std::cout << "lvalue (or const)\n"; }
void take(std::string&&) { std::cout << "rvalue — can steal its guts\n"; }
int main() {
std::string s = "hi";
take(s); // lvalue
take(std::string("tmp")); // prvalue (temporary)
take(s + "!"); // result of an expression is a temporary
take(std::move(s)); // std::move casts s to an rvalue (xvalue)
}lvalue (or const)
rvalue — can steal its guts
rvalue — can steal its guts
rvalue — can steal its guts| Reference | Binds to lvalue | Binds to rvalue | Typical use |
|---|---|---|---|
T& | Yes | No | Modify caller's object |
const T& | Yes | Yes | Read-only parameter, no copy |
T&& | No | Yes | Move constructors, sink parameters |
auto&& / T&& in a template | Yes | Yes | Forwarding (“universal”) reference |
Dangling references
#include <iostream>
#include <vector>
int main() {
std::vector<int> v{1, 2, 3};
int& ref = v[0];
v.push_back(4); // may reallocate: ref now refers to freed memory
std::cout << ref << '\n'; // AddressSanitizer: heap-use-after-free
}Can a reference be null?
What does it mean that std::move doesn't move anything?