【ChernoC++笔记】左值和右值
左值和右值#
❓什么是左值和右值?#
- 大多数情况下,左值在等号左边,右值在右边。例如
int i = 10;
中变量i
是左值,在内存中有实际的位置,通常有较长的生命周期;10是右值,没有存储空间,只是数字字面量,生命周期很短,通常是临时的。 - 只能给左值赋值,不能写成
10 = i;
因为10没有位置,不能在10中存储数据。 - 等号右边不一定是右值,例如
int a = i;
中,i
就是之前的有实际位置的左值。
▶️当右值是函数的返回值#
int GetValue() {
return 10;
}
int main() {
int i = GetValue();
GetValue() = 5; // error
}
GetValue()返回一个右值,它是一个临时值,没有存储位置。
如果写了GetValue() = 5;
编译器会报错error: lvalue required as left operand of assignment
,也就是赋值的左操作数需要左值。
左值引用#
▶️通过左值引用使GetValue()
返回左值,它就可以被赋值。#
int& GetValue() {
static int value = 10;
return value;
}
int main() {
int i = GetValue();
GetValue() = 5; // fine
}
❓左值引用可以被右值赋值吗?#
void SetValue(int& value) {}
int main() {
int i = 10;
SetValue(i);
SetValue(10); // error
}
不能使用SetValue(10)
,编译器报错:非常量引用的初始值必须为左值。
即,无法接受int& a = 10
(使用右值来赋值左值引用)。
▶️通过常量引用解决该问题:#
const int& a = 10; // fine
实际上,编译器可能用实际的存储创建了该临时变量,然后赋值给引用,即
int temp = 10; // 创建了一个左值
const int& a = temp;
将上面的SetValue()参数也加上const,就可以同时接受左值和右值。
void SetValue(const int& value) {}
int main() {
int i = 10;
SetValue(i); // fine
SetValue(10); // fine
}
▶️字符串的例子#
std::string firstName = "Yan";
std::string lastName = "Chenikov";
std::string fullName = firstName + lastName;
firstName + lastName
是一个右值:虽然字符串字面量是左值,但+
操作符返回的是临时量,为右值。
void PrintName(std::string& name) {
std::cout << name << std::endl;
}
int main() {
std::string firstName = "Yan";
std::string lastName = "Chenikov";
std::string fullName = firstName + lastName;
PrintName(fullName); // fine
PrintName(firstName + lastName); // error
}
无法Print(firstName + lastName);
,因为不能使用右值来给左值引用赋值。
void PrintName(const std::string& name) {
std::cout << name << std::endl;
}
int main() {
std::string firstName = "Yan";
std::string lastName = "Chenikov";
std::string fullName = firstName + lastName;
PrintName(fullName); // fine
PrintName(firstName + lastName); // fine
}
参数加上const
之后(即常量引用),可以兼容临时的右值和实际存在的左值变量。
右值引用#
❓写一个只接受临时对象的函数? ➡️➡️右值引用#
// 右值引用是两个&&
void PrintName(std::string&& name) {
std::cout << name << std::endl;
}
int main() {
std::string firstName = "Yan";
std::string lastName = "Chenikov";
std::string fullName = firstName + lastName;
PrintName(fullName); // error
PrintName(firstName + lastName); // fine
}
此时,PrintName(std::string&& name)
函数可以接受右值,但不接受左值,编译器报错:无法将右值引用绑定到左值。
void PrintName(const std::string& name) {
std::cout << "[lvalue] " << name << std::endl;
}
void PrintName(std::string&& name) {
std::cout << "[rvalue] " << name << std::endl;
}
int main() {
std::string firstName = "Yan";
std::string lastName = "Chenikov";
std::string fullName = firstName + lastName;
PrintName(fullName); // [lvalue] YanChenikov
PrintName(firstName + lastName); // [rvalue] YanChenikov
}
即使PrintName(const std::string& name)
也可以接受右值,但传入右值时,仍会选择第二个重载的函数PrintName(std::string&& name)
。
❓右值引用有什么用?#
优化技巧:处理右值引用时,可以检测到传入的是一个临时对象,从这个临时值中“偷”资源。
-->*移动语义
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!