首先,要分清楚左值和右值,一般来说左值和右值是等式的左边和右边,但也存在部分特殊情况导致左值和右值不一定必须在等式的左边和右边,比如使用move()函数,使用?:条件表示式时,数组访问等等。如有不对,请在评论区指点,本人刚入门
1.int arr[5] = {1, 2, 3, 4, 5};
int e = arr[2]; // 左值 `arr` 在数组访问表达式的右侧
2.int b = (a > 0) ? a : -a; // 左值 `a` 在条件表达式的右侧
3.struct Point { int x, y; };
Point p = {1, 2};
int d = p.x; // 左值 `p` 在成员访问表达式的右侧
4.#include <utility> // for std::move
struct MyStruct {
int value;
// Copy assignment operator with an rvalue reference qualifier
MyStruct& operator=(MyStruct&& other) & {
value = other.value;
return *this;
}
};
int main() {
MyStruct a{10}, b{20};
a = std::move(b); // Right value of 'b' being assigned to 'a' using move semantics
return 0;
}//尽管b本身是一个左值,但通过std::move转换后,它的值可以被移动到a中,而不是复制。这展示了右值在特定条件下可以出现在等式的左侧。
若使用move()函数,一般都需要先行了解移动语义,move()函数类似于在计算机移动文件的情形:实际文件还留在那个地方,而只是修改记录这种方法被称为移动语义。移动语义实际上避免了移动原始数据,而只是修改了记录 ,可以明显提高运行速度。
使用move()函数需要添加utility头文件
其次
1.左值指的是一个指向特定内存的值,有一个稳定的内存地址,并且短时间内不会被销毁,具有较长的生命周期
int a=10;//a是一个左值
int b=a;//a也可以作为一个右值使用,但a和b本质上都是左值
5=a;//错误,5作为一个数字字面值,不能被赋值,数字字面值没有较持久的内存地址
2.右值指的是不指向稳定内存地址的匿名值,周期很短,用完就被销毁
如(1)表达式计算:都是临时的,不能被取地址,不能被赋值
(5+100)*12;
int a=10;
a+10;
5;
(2)函数返回的值:同上
int func(){
return 10;
}
func();
(3)移动构造参数和移动赋值运算符的参数 :move函数将str作为右值返回给str1
string str="example";
string str1=std::move(str)//move函数返回一个右值
最后
无论是左值引用还是右值引用在声明时都必须被初始化,否则会造成悬空引用,这是一种未定义行为,会导致程序崩溃或其他不可预测现象
常量左值可以引用非常量和常量左值,非常量左值只能引用非常量左值
int a=10;
const int c=10;
int &b=a//正确可以引用
int &b=c//错误,非常量左值只能引用非常量
const int &b=a;//正确
常量右值只能引用常量右值,不能引用常量左值
int a=10;
const int c=10;
int &&b=a;//报错
int &&b=c;//报错
int &&b=10;//正确,可以绑定一个临时变量
const int &&b=a;//错误不支持引用非常量左值
const int &&b=c;//报错,不支持引用常量左值
const int &&b=100;//正确
作者水平有限,如有大神可在评论区补充,我会一一学习