左值引用和右值引用
左值和右值的定义
关于左值的定义,在《C++ Primer Plus》当中是这样定义的
左值是什么呢?左值参数是可被引用的数据对象,例如,变量、数组元素、结构成员、引用和解除引用的指针都是左值。非左值包括字面
常量(用引号括起的字符串除外,它们由其地址表示)和包含多项的表达式(例如x+y,函数的返回值)。在C语言中,左值最初指的是可出现在赋值语句左边的实体,但
这是引入关键字const之前的情况。现在,常规变量和const变量都可视为左值,因为可通过地址访问它们。但常规变量属于可修改的左值,而
const变量属于不可修改的左值。
提炼出关键区别可得出:可以直接通过地址访问的都是左值,不可以通过地址访问的是右值。左值又因为const分为可修改和不可修改两种。
举例如下:
int a=10;//a是左值,实际定义的时候是分配了一段地址,给起名为a,所以访问a就是访问这个地址
//而10这个只是一个字面值,没有给他分配实际的地址,无法在其他地方访问到这个10
int &b=a;
int* p = &b; //此时的引用b和*p其实指向的都a这块内存,是可以通过地址访问的
const char *str ="ABC"//此处的ABC虽然也是字面值,但是他其实在常量,实际也是有地址,所以是左值
int a=b+c;//b+c也是一个右值
int a=fun(void)// 函数的返回值是右值
左值引用和右值引用的定义
左值引用
左值引用是我们最传统的的引用,引用是给一个已经定义变量起别名。这种引用的一个主要用途就是作为函数的形参,通过引用变量做形参,让函数操作这个函数的原始
数据。左值引用的在创建的时候必须初始化,而且初始话后不能被改变。左值引用在本质上是一个指针常量,所以函数不能返回一个本地变量的引用。
int a=10;
int &b=10;//错误,绑定的对象不是左值
int &b=a;//创建的时候必须绑定一个左值
int *const ref=&a;//此处的ref等价于b
void fun(const int &c);//常量引用,用作形参,防止引用绑定的对象的值被改变
const int &d=10;//此处是常量引用,此处的10是有地址的,在const区域
右值引用
右值引用是C++11新增的一种引用,他可以绑定到一个右值。右值引用实质上是给一个右值(本没有地址,更无法通过地址访问)划分一块地址,以后可以通过访问该右值引用(新划的地址)来访问这个右值。
int &&a=10;
int &b=a;//此处是一个左值引用,因为a已经有了地址
std::cout << a << std::endl;//打印10
std::cout << &a << std::endl;//本来一个右值10是没有地址的,但是我们给他使用了右值引用了以后就可以打印出他的地址以及打印出他的值了
int &&b=x+y;//此时的b只是获取当下x+y的值,以后x或y改变了,也不会改变b的值
i++与++i的分析
++i 是先加后用,先对i进行+1,然后返回i,此时返回的是一个左值,自始至终都是一个变量i
i++是先用后加,会先产生一个临时变量来保存i的值,以供使用,然后再给原来的i的值+1,还是保存在原来i的空间,但是返回的却是那个临时变量(即未自增前的变量),之后这个临时变量就会被释放,因此是
右值表达式。
由上图的这个例子可以看出,无论是i++还是++i,运行后i的值都会自增,对于i++这种情况,他会有一个临时变量才存储原来的值,因此会调用一次拷贝构造函数,导致性能的损失。
移动语义
引入右值引用的一个目的是为了实现移动语义
std::move()
move的作用是把一个左值强制变成一个右值
TODO:找到那天的临时笔记