关于lvalue和rvalue引用的困惑:为何rvalue引用变量被当作lvalue处理?
左值引用与右值引用的核心疑问
我难以理解左值(lvalue)和右值(rvalue)引用,以下是我的代码示例:
#include <iostream> // 返回右值 int Add(int x, int y) { return x + y; } // 返回左值 int & Transform(int &x) { x *= x; return x; } void Print(int &x) { std::cout << "Print(int&) L value ref" << std::endl; } void Print(const int &x) { std::cout << "Print(const int&) const l value ref" << std::endl; } void Print(int &&x) { std::cout << "Print(int &&) r value ref" << std::endl; } int main() { // x是左值 int x = 10; // ref是左值引用 int &ref = x ; // Transform返回左值 int &ref2 = Transform(x) ; // 绑定到接受左值引用的函数 Print(x); Print(ref); Print(ref2); // rv是右值引用 int &&rv = 8 ; // Add返回临时对象(右值) int &&rv2 = Add(3,5) ; // 绑定到接受临时对象的函数,即右值引用重载 Print(3); Print(rv); Print(rv2); return 0; }
运行后输出:
Print(int&) L value ref Print(int&) L value ref Print(int&) L value ref Print(int &&) r value ref Print(int&) L value ref Print(int&) L value ref
我大致能理解前4条输出,但最后两条中,rv和rv2是右值引用,为何它们会被传递到接受左值引用的Print函数?
核心原因:命名的右值引用本身是左值
这里的关键规则是:所有命名的变量(包括右值引用变量)在表达式中都是左值。
- 当你写
int &&rv = 8;时,rv是一个有名字的右值引用变量,它绑定了临时值8,但一旦这个引用有了名字,它就变成了可以被取地址、被修改的左值——因为你能通过名字反复访问它,它不再是“临时的、只能用一次”的右值。 - 所以当你调用
Print(rv)或Print(rv2)时,编译器会把它们当作左值处理,因此匹配接受左值引用的Print(int&)重载,而不是右值引用的Print(int&&)。
如果想让右值引用变量以右值的身份传递,需要用std::move()将其转换为右值,比如:
Print(std::move(rv)); // 此时会匹配Print(int&&) Print(std::move(rv2)); // 同理
内容的提问来源于stack exchange,提问作者KansaiRobot
相关产品推荐
相关产品推荐

