左值,右值,左值引用,右值引用
介绍
左值(Lvalue)
左值是可以出现在赋值语句左边的表达式。具有以下特征:
- 有持久的内存地址
- 可以被取地址
- 可以被赋值
int x = 10; // x是左值
int* ptr = &x; // 可以取x的地址
x = 20; // 可以被赋值
右值(Rvalue)
右值是只能出现在赋值语句右边的表达式。具有以下特征:
- 临时的
- 不可取地址
- 不可被赋值
int y = x + 5; // (x + 5)是右值
int z = 10; // 10是右值
左值引用(Lvalue Reference)
左值引用是传统的引用,使用 & 符号声明。
- 只能绑定到左值
- 可以读写原始对象
- 不能绑定到右值(C++11之前)
int x = 10;
int& ref = x; // ref是x的左值引用
ref = 20; // 通过引用修改原值
右值引用(Rvalue Reference)
右值引用是C++11引入的新特性,使用 && 符号声明。主要用于移动语义和完美转发。
- 可以绑定到右值
- 主要用于移动语义和完美转发
- 可以“窃取“临时对象的资源
int&& rref = 10; // 右值引用
右值引用的主要应用场景
移动语义
class MyString {
public:
// 移动构造函数
MyString(MyString&& other) noexcept {
// 直接转移资源,避免深拷贝
}
};
完美转发
template<typename T>
void wrapper(T&& arg) {
// 完美转发参数
foo(std::forward<T>(arg));
}
左值和右值的转换
int x = 10;
int&& rref = std::move(x); // 将左值x转换为右值引用
实际应用示例
#include <iostream>
#include <utility>
void processValue(int& x) {
std::cout << "Lvalue reference" << std::endl;
}
void processValue(int&& x) {
std::cout << "Rvalue reference" << std::endl;
}
int main() {
int a = 10;
processValue(a); // 调用左值引用版本
processValue(10); // 调用右值引用版本
processValue(std::move(a)); // 调用右值引用版本
return 0;
}
总结
- 左值:有标识符,可寻址
- 右值:临时的,不可寻址
- 左值引用:传统引用,绑定左值
- 右值引用:C++11特性,支持移动语义和完美转发
- std::move() 可以将左值转换为右值引用
- 右值引用支持移动构造和移动赋值,减少不必要的内存拷贝
用法
左值,右值
C++任何一个对象要么是左值,要么是右值 int i = 10,i 和 10 都是对象,i是左值,10是右值;
左值:拥有地址属性的对象就叫左值,左值来源于c语言的说法,能放在“=”左面的就是左值,注意,左值也可以放在“=”右面。
右值:没有地址属性的对象就叫做右值,注意,右值绝对不可以放在等号左面
有地址属性,就代表可以操作地址,没有地址属性,就无法操作操作地址;
一般来说, 判断一个对象是左值还是右值,就看对象有没有地址属性。
比如临时对象,就都是右值,临时对象没有地址属性,无法操作地址。 注意:左值也可以放在“=”右面,但右值绝对不可以放在等号左面
小测验:
#include <iostream>
int main() {
int i = 10;
int i2 = (i + 1); // i + 1 临时对象 右值
++i = 200; // ++i 先给i加1,然后返回i,i是有地址的,左值
i++; // i++ 先返回一个临时变量,临时变量的值 = i的值,然后临时变量的值 + 1
// 返回的是临时变量,当然无法使用地址
return 0;
}
引用分类
普通左值引用:就是一个对象的别名,只能绑定左值,无法绑定常量对象
#include <iostream>
// 因为引用相当于别名,如果这里可以绑定的话,
// 我们只要修改refI的值,那么i的值可以绕过这个const修饰符而被修改,那么const就没有意义了
int main() {
const int i = 100;
int& refI = i; // 非法,左值引用不允许绑定常量对象
refI = 200;
int j = 100;
int& refJ = j; // 合法
return 0;
}
const 左值引用:可以对常量起别名,可以绑定左值和右值
#include <iostream>
int main() {
const int i = 100;
const int& refI = i; // 绑定左值 合法
const int& refI1 = (i + 1); // 绑定右值 合法;
return 0;
}
右值引用:只能绑定右值的引用
#include <iostream>
// 右值引用 只能绑定右值
int main() {
int i = 100;
int&& rrefI = 200; // 右值引用,绑定右值合法
int&& refI1 = i; // 右值引用,绑定左值不合法
return 0;
}
左值引用与右值引用的区别?右值引用的意义?
https://www.bilibili.com/video/BV1eN4y1R7Me?spm_id_from=333.788.videopod.sections&vd_source=cb02f779bd17a3aad9801e0c4464dfc9