一.【左值&左值引用】&【右值&右值引用】
【1】左值&左值引用
左值:
- 左值是一个表示数据的表达式
- 如: 变量名或解引用的指针
- 出现位置:左值 可以出现在赋值符号的左边,右边
- 性质1:左值可以 取地址+可以对它赋值
- 性质2: 定义时const修饰符后的左值 , 不可以对它赋值 ,但是 可以对它取地址
左值引用:
- 左值引用就是给左值的引用,给左值取别名
int a = 0; int& r1 = a;
- 代码演示如下:
int main() { // 以下的ptr、b、c、*p,都是左值 int* ptr = new int(0); int b = 1; const int c = 2; "xxxxx"; const char* p = "xxxxx"; //左值可以取地址 cout << &("xxxxx") << endl; //左值引用演示 int a = 0; int& r1 = a; }
【2】右值&右值引用
右值:
- 右值也是一个表示数据的表达式
- 如: 字面常量、表达式返回值,函数返回值(这个不能是左值引用返回)等等、
- 出现位置: 右值可以出现在赋值符号的右边, 但是不能出现出现在赋值符号的左边
- 性质: 右值不能取地址
普通右值&将亡值:
我们一般把右值分为如下两类:
- 普通右值
- 将亡值,例如:
fun( )
右值引用:
- 右值引用就是对右值的引用,给右值取别名
- 例如:
int&& r5 = 10;
- 代码演示如下:
int main() { //以下均为右值 10; x + y; fmin(x, y); //右值无法取地址 // cout << &10 << endl; // cout << &(x+y)<< endl; // cout << &(fmin(x, y)) << endl; // 以下几个都是对右值的右值引用 int&& rr1 = 10; double&& rr2 = x + y; double&& rr3 = fmin(x, y); }
二.左值引用右值&右值引用左值の规则
基本规则:
- 引用是 取别名
- 左值引用:给左值取别名————————(1)正常左值引用(2)带const的左值引用
- 右值引用:给右值取别名
move( )
可以让里面的值具有 右值性质
左值引用右值&右值引用左值の总结:
int main() { double x = 1.1, y = 2.2; // 左值引用:给左值取别名 int a = 0; int& r1 = a; // 左值引用能否给右值取别名? // const左值引用可以 const int& r2 = 10; const double& r3 = x + y; // 右值引用:给右值取别名 int&& r5 = 10; double&& r6 = x + y; // 右值引用能否给左值取别名? // 右值引用可以引用move以后的左值 int&& r7 = move(a); return 0; }
三.move函数
引入:按照语法,右值引用只能引用右值,但右值引用一定不能引用左值吗?
- 因为:有些场景下,可能真的需要用右值去引用左值实现移动语义。当需要用右值引用引用一个左值时,可以通过move函数将左值转化为右值。
- C++11中,std::move()函数位于 头文件中,该函数名字具有迷惑性,它并不搬移任何东西,唯一的功能就是将一个左值强制转化为右值引用,然后实现移动语义。
int main() { bit::string s1("hello world"); // 这里s1是左值,调用的是拷贝构造 bit::string s2(s1); // 这里我们把s1 move处理以后, 会被当成右值,调用移动构造 // 但是这里要注意,一般是不要这样用的,因为我们会发现s1的 // 资源被转移给了s3,s1被置空了。 bit::string s3(std::move(s1)); return 0; }
- 为什么s1会置空呢?让我们看看接下来一篇博客: