右值
右值
每个 C++ 表达式都有一个类型,属于值类别。 值类别是编译器在表达式计算期间创建、复制和移动临时对象时必须遵循的规则的基础。
C++17的值类别有:
- glvalue (generalized lvalue):表示对象身份的表达式,如变量名、函数名、类名等(包括具名右值引用,匿名右值引用比如std::move(x)是右值)。
- prvalue (pure rvalue):表示纯右值的表达式,如字面量、临时对象等。没有可供程序访问的地址。包括文本,返回非引用引用的函数调用,只有编译器访问的临时资源。
- xvalue (expiring value):表示一个对象或位域,该对象或位域的资源可重复使用(通常是因为它接近其生存期的末尾)。有地址,但地址不再供程序访问,但可以用于初始化rvlaue引用。比如返回右值引用的函数调用。
- lvalue (lvalue):表示一个对象或位域,该对象或位域具有标识符并且可用作左值。具有程序可访问的地址。
- rvalue (rvalue):prvalue 或 xvalue。
右值包括字面常量和求值过程中创建的临时对象,这些对象将要被销毁且没有其他用户。
函数参数都是左值。
右值引用
绑定到右值的引用。只能绑定到将要销毁的对象,因此可以将右值引用的资源移动到另一个对象中。
右值引用可以延长临时对象的生命周期(常量左值引用也可以),直到右值引用结束。
move
利用移动语义,可以编写将资源(如动态分配的内存)从一个对象转移到另一个对象的代码,允许从临时对象(无法在程序中的其他位置引用)转移资源。
move用于获得绑定到左值的右值引用,告诉编译器希望像右值一样处理左值,并承诺不再使用该左值(可以销毁移后对象,也可以赋予新值,但是不能使用移后源对象的值)。
使用时应该直接调用std::move而不是move,避免潜在名字冲突
引用折叠
参数推断:将左值传递给右值引用参数T&&时,T被推导为左值引用类型。
创建引用的引用形成了折叠
- T& &、T& &&、T&& & 都折叠为T&
- T&& &&折叠为T&&
结合上面两条
template
void f(T&&)
对该函数传递左值,会实例化出
void f<int&>(int&)
所以实际上我们可以把任何类型的参数传递给T&&类型的函数。
需要注意的是,传递左值引用时,函数内部可能造成错误的效果,因此使用下面的方式进行重载。
以下两个模板能适用于所有类型的参数,但是对不同类型的匹配程度不同,因此会优先匹配更精确的模板。
template
void f(T&&) // 非const右值,右值精确匹配,可以窃取资源
templatevoid f(const T&) //左值和const右值
move源码
template <typename T>
typename remove_reference<T>::type&& move(T&& param)
{
return static_cast<typename remove_reference<T>::type&&>(param);
}
根据以下例子进行分析
string s1("hi"), s2;
s2 = move(string("bye"));
s2 = move(s1);
第一个赋值
- T为string
- param为string&&
- remove_reference
::type为string - 返回类型为string&&
因此实例化为
string&& move(string&& param)
static_cast转换什么都不做
第二个赋值
- T为string&
- param为string&
- remove_reference
::type为string - 返回类型为string&&
因此实例化为
string&& move(string& param)
使用static_cast将左值转换为右值引用是允许的。
forward
函数参数为T&&时,无论传递的实参是左值还是右值,函数内部该参数都是左值,导致内部调用其他函数时右值引用的参数无法接受左值。
某些函数将一个或多个实参联通类型不变地转发给其他函数,需要保持实参的所有性质,包括是否为const以及左值或右值。
forward使用显式模板实参来调用,返回显式实参的右值引用。即forward
template <typename T>
intermediary(T&& param)
{
finalFcn(forward<T>(param));
}
实参为右值时,T被推导为非引用类型,因此forward
实参为左值时,T被推导为左值引用类型,因此forward
从现象上看和'static_cast<T&&> (param)'效果一样。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了