左值引用&右值引用
值类别和变量类型,生命周期
左值引用
对于非const的左值引用,只能匹配左值。对于const的左值引用(也叫 常引用),可以匹配左值和右值
int a = 3;
int& ra = a; // 只能匹配左值
const int& cra = 10; // 可以匹配右值
右值引用
初始化
右值引用仅可使用 rvalue 进行初始化
Foo func2()
{
Foo f1("AAA");
return f1;
}
int main()
{
int && r1 = 3; // 1. 引用字面量
Foo && r2 = func2(); // 2. 引用临时变量(函数返回值)
Foo && r3 = Foo("BBB"); // 3. 引用临时变量(匿名变量)
Foo f("CCC");
Foo && r4 = std::move(f); // 4. 引用std::move的强制左值
return 0;
}
值类别(value category) 和 变量类型 (variable type)
值(value) 和 变量(variable) 是两个独立的概念。
- 值 只有 类别 (category) 的划分,变量 只有 类型 (type) 的划分
- 值 不一定拥有 身份 (identity),也不一定拥有 变量名(例如 表达式中间结果 i + j + k)
值类别可以分为五种: lvalue, xvalue, prvalue, glvalue, rvalue.
引用类型(Reference declaration)属于一种变量类型, ex: 左值引用,右值引用,常引用。
Foo&&类型只是指明变量类型,并不能区分左右值。就好像对于int i = 3; 一样,=的左右都是int类型,但是左侧的i是左值,右侧的3的右值(prvalue)。
右值引用初始化
右值引用和左值引用比起来,不同的地方在于初始化那一刻:右值引用必须通过右值来初始化。初始化完成之后,就没有什么特殊的了。
C++11有一个规则:右值引用类型(形如Foo&&)的表达式,有名字的是左值;没有名字的是右值。其实这也可以类比其他类型,命名变量(如局部变量、形参、全局变量)是左值;匿名变量(没有名字)是右值。
生命周期
通过 右值引用/常引用 初始化的右值,都可以将 生命周期扩展 (lifetime extension) 到 绑定该右值的 引用的生命周期
class Bar {
private:
string s;
public:
Bar(string a) : s(a) {
cout << "Bar(string) " << s << endl;
}
~Bar() {
cout << "~Bar() " << s << endl;
}
};
int main() {
Bar("a");
Bar&& rfb = Bar("b");
cout << "end" << endl;
}
// Output
// Bar(string) a
// ~Bar() a
// Bar(string) b
// end
// ~Bar() b
对于a未被引用的右值, 在执行完当前行后,就会被析构。对于被rfb的右值引用的b,生命周期绑定至rfb的生命周期
ref
- https://www.yuanguohuo.com/2018/05/25/cpp11-rvalue-ref/
- https://murphypei.github.io/blog/2020/02/right-reference




