一、左值引用
#include <iostream>
using namespace std;
void change(int & rnum)
{
rnum = 111;
}
void main()
{
int num(10); //num是左值,有内存实体
int &rnum(num); //rnum变量的别名,&是引用
rnum = 1; //rnum等价于num1的别名,操作别名,就是操作实体
cout << num << endl; //1
change(num);
cout << num << endl; //111
cin.get();
}
总结:
- 左值:有内存实体
- 引用,给变量起别名,引用就是操作内存实体
- 引用可以作为函数传参,引用传参相当于函数传参,也是操作内存的实体
- 能引用别指针
- 左值引用就是#
二、什么是右值
#include <iostream>
//右值引用
void main()
{
int num = 1;
int data = 0;
std::cout << (void *)&data << std::endl;
data = num + 1; //num + 1是在寄存器里面的操作,没有在内存里面操作,因此它是右值
data = num + 2;
data = num + 3;
std::cin.get();
}
总结
- 右值没有内存实体,是在寄存器里面操作
三、左右值引用对比
#include <iostream>
void main()
{
int num = 1;
int && runm(num + 4); //右值引用,只需要一次,快速备份,编译器如果没有使用就自动回收
std::cout << runm << std::endl;
int data1 = num + 4; //第一步
int & runmx(data1); //第二步,左值引用,需要两步,效率低
//&是左值引用,&&是右值引用
std::cin.get();
}
总结:
- &是左值引用,&&是右值引用
- 右值引用,可以快速备份数据
- 引用符号&和&&如何插入:数据类型 &|&& 变量名
四、引用指针
引用指针,相当于二维指针,如果想要修改指针的指向,传递指针的引用[函数传参]
#include <iostream>
void main()
{
int a[5]{ 1, 2, 3, 4, 5 };
int *p(a); //p指向数组a的地址,*p = 1;
p += 1; //p是第一个原始的地址,+1就是移动一个元素
std::cout << *p << std::endl; //因此*p=2;
int * & rp(p); //左值引用改变指针, &放在类型与变量名之间,p有内存实体,因此是左值
rp += 1; //rp是p的别名,因此rp += 1;相当于p += 1;
std::cout << *p << std::endl; //p原来指向2,现在指向3
int * && rrp(p - 2); //p-2是在寄存器里面进行操作的,因此是右值
rrp += 2; //rrp是p-2的别名,因此 p-2 +=2;
std::cout << *rrp << std::endl;
std::cin.get();
}
五、移动语义
#include <iostream>
using namespace std;
//左值引用引用内存里面的值,右值引用引用寄存器里面的值
void showit(int && rrnum)
{
cout << rrnum << endl;
}
void showitz(int & rrnum)
{
cout << rrnum << endl;
}
void main()
{
int a[5]{ 1, 2, 3, 4, 5 };
showit(a[3] + 2); //a[3]+2=4+2=6,在寄存器里面产生,是右值引用,可以节约内存
showit(move(a[3])); //move移动语义,把左值转换为右值
showitz(a[3]);
cin.get();
}
总结:
左值引用和右值引用的区别
- 左值&,右值&&
- 左值有内存实体,右值没有内存实体
- 右值引用只需一步,左值需要两步,右值可以快速备份数据,编译器如果没有使用,就自动回收
- move移动语义,把左值转换为右值
- 引用指针相当于指针的指针,可以改变指针指向