一、左值、右值
1、左值:放在赋值语句左边的变量,是内存的“代理人”。左值实质指的是内存区域,放在“=”左边,将右边表达式的计算结果写入内存,只是用变量名来代表内存区域
int age = 10;
2、右值:表达式 or 常数
3、变量包含两个要素
a、内存区域,可以理解为左值
b、存储的数据(存的值),可以理解为右值
变量可以即为左值又为右值(读取该变量所代表内存的数据)。
∴ int myAge = age + 8; // 此时age 用的是它的右值属性
4、对变量的修改都要通过左值(写入到内存,更新值)
二、引用:一种隐式指针
引用:主要用来定义函数的参数、函数返回类型,可以提高效率。
以前只允许给变量的左值定义别名,称为引用(也叫左值引用)。后来为了给表达式、常量和变量的右值定义别名,创造了右值引用。
1、引用和指针的区别
指针是一个变量,且占用内存;指针可以再指向别的地址(注意const)。引用是别名,不占内存,必须在定义时进行初始化,且不能作为其他变量的引用。
注:不能建立引用数组:引用不分配内存(不能创建指向引用的指针),一次只能为一个已有变量定义一个别名,而数组一次需要定义多个元素,因此矛盾。
int a[3] = {1,2,3};
int *b[3];
int (&ra)[3] = a;
int *(&pra)[3] = b;
int &ia[3] = a; // error —— ia 是引用数组,每个数组元素都是引用
2、左值引用
int a = 1;
int &b = a; // a、b可以认为没有任何差别,是同一个内存区域的两个别称。
a.在变量声明(带着int、float这类)时出现的&才是引用,其他地方出现的时取地址
b.引用必须在定义时初始化,并可赋值为其他引用
3、右值引用 &&
绑定到右值上的引用。只能绑定到即将消亡的对象上,以支持移动操作。
int a = 3;
int &&x = a; // 错,变量名对应变量的左值,只能绑定为左值引用。
int &&y = a + 30; // 对,y 代表表达式“a + 30;”的右值引用
系统为了保存表达式"a + 30"的计算结果而创建无名临时对象,y对应该对象。该对象只有短暂的生存期,它的值被取用后,立马销毁收回内存区域。y延长了临时变量的生存期,接管了该临时对象。
三、移动函数
为解决临时对象的复制问题(如函数返回一个对象),提出移动对象技术。本质把某对象的内存资源“转让”给另外一个对象。
变量名对应内存的左值,不能直接绑定到右值,需利用move()函数。
int a = 1;
int &&x = a; // 错,变量名是左值,不能绑定右值
int &&y = std::move(x); // 对
// case
class A {...};
A a;
A &&x = a; // 错
A &&y = move(a); // 对
1、移动赋值运算函数、移动拷贝构造函数
class A {
...
A(A &&x) {...} // 移动构造函数
A &operator=(A &&x) {...} // 移动赋值运算符
};
参看:《C++面向对象程序设计》