左值与左值引用
左值
左值就是在内存中有确定存储位置,有变量名,表达式结束后依然存在的值。
左值引用
左值引用就是绑定到左值上的引用。
左值引用的绑定
非常量左值引用只能绑定到非常量左值上;
常量左值引用可以绑定到非常量左值、常量左值、非常量右值、常量右值等所有的值类型。
1 | int a=10; //非常量左值(有确定存储地址,也有变量名) |
右值与右值引用
右值
右值就是在内存没有确定存储地址、没有变量名,表达式结束就会销毁的值。
右值引用
右值引用就是在内存中没有确定存储位置,没有变量名,表达式结束后就会销毁的值。
右值引用的绑定
非常量右值引用只能绑定到非常量右值上;
常量右值引用可以绑定到非常量右值、常量右值上。
1 | int a=10; //非常量左值(有确定存储地址,也有变量名) |
区别
左值引用绑定到有确定存储空间以及变量名的对象上,表达式结束后对象依然存在;右值引用绑定到要求转换的表达式、字面常量、返回右值的表达式等临时对象上,赋值表达式结束后就对象就会被销毁。
左值引用后可以利用别名修改左值对象;右值引用绑定的值不能修改。
move函数
从上述可以发现,常量左值引用可以绑定到右值上,但右值引用不能绑定任何类型的左值,若想利用右值引用绑定左值该怎么办呢?
C++11中提供了一个标准库move函数获得绑定到左值上的右值引用,即直接调用std::move告诉编译器将左值像对待同类型右值一样处理,但是被调用后的左值将不能再被使用。
1 | int a=10; //非常量左值(有确定存储地址,也有变量名) |
引入右值引用的原因
替代需要销毁对象的拷贝,提高效率:某些情况下,需要拷贝一个对象然后将其销毁,如:临时类对象的拷贝就要先将旧内存的资源拷贝到新内存,然后释放旧内存,引入右值引用后,就可以让新对象直接使用旧内存并且销毁原对象,这样就减少了内存和运算资源的使用,从而提高了运行效率;
移动含有不能共享资源的类对象:像IO、unique_ptr这样的类包含不能被共享的资源(如:IO缓冲、指针),因此,这些类对象不能拷贝但可以移动。这种情况,需要先调用std::move将左值强制转换为右值,再进行右值引用。