Cpp中的各种引用

引用不能引用数组

引用大小测试

class MyClass
{
    char &  a;                                                                                                                                                                                                      
    char &  b;  
    char & c;//引用的本质是指针,直接sizeof引用,就是求引用的数据大小
	//引用变量占据8个字节,平台为liunx X86_64
};
int main()
{
    int num = 10; 
    int & rnum(num);
    double db = 10.9;
    double & rdb(db);//直接作用引用的变量
    //测试引用变量所占的大小
    std::cout << sizeof(rnum) << std::endl;//sizeof直接作用于引用的变量所以大小为该类型数据的值
    std::cout << sizeof(rdb) << std::endl;
    std::cout << sizeof(MyClass) << std::endl;
    return 0;
}
out:
4
8
24

左值引用

返回栈中数据
局部基本数据类型
//该程序运行会产生段错误,原因是访问了已经释放的栈变量
int&  mac()
{
	int num=10;
	return num;
}

int main()
{
   	//用基本数据来接收返回值
	int i=mac();//用引用来接收返回值
    int &p=mac();
   cout<<p<<endl;
	cout<<i<<endl;
	return 0;
}

asm:#无关代码已略去
Dump of assembler code for function main():
...
   0x0000555555554a3c <+8>:	call   0x555555554955 <mac()>
   0x0000555555554a41 <+13>:	mov    eax,DWORD PTR [rax]
   0x0000555555554a43 <+15>:	mov    DWORD PTR [rbp-0xc],eax
   0x0000555555554a46 <+18>:	call   0x555555554955 <mac()>
=> 0x0000555555554a4b <+23>:	mov    QWORD PTR [rbp-0x8],rax
...
   0x0000555555554aa4 <+112>:	ret    
End of assembler dump.
 
       //实际gcc编译生成的汇编不是如此,此处是使用全局num生成的汇编,
Dump of assembler code for function mac():
   0x0000555555554955 <+0>:	push   rbp
   0x0000555555554956 <+1>:	mov    rbp,rsp
   0x0000555555554959 <+4>:	mov    DWORD PTR [rip+0x2017d1],0xa        # 0x555555756134 <num>
   0x0000555555554963 <+14>:	lea    rax,[rip+0x2017ca]        # 0x555555756134 <num>
=> 0x000055555555496a <+21>:	pop    rbp
   0x000055555555496b <+22>:	ret    
End of assembler dump.
       vs2015中反汇编mac
       00F721F8 C7 45 F4 0A 00 00 00 mov         dword ptr [num],0Ah  
    	int i = (int)&num;
00F721FF 8D 45 F4             lea         eax,[num]  
00F72202 89 45 E8             mov         dword ptr [i],eax  
     	return num;
00F72205 8D 45 F4             lea         eax,[num]  
gdb中反汇编
    Dump of assembler code for function mac():
   0x00005555555549e8 <+0>:	push   rbp
   0x00005555555549e9 <+1>:	mov    rbp,rsp
   0x00005555555549ec <+4>:	sub    rsp,0x10
   0x00005555555549f0 <+8>:	mov    rax,QWORD PTR fs:0x28
   0x00005555555549f9 <+17>:	mov    QWORD PTR [rbp-0x8],rax
   0x00005555555549fd <+21>:	xor    eax,eax
   0x00005555555549ff <+23>:	mov    DWORD PTR [rbp-0xc],0xa
=> 0x0000555555554a06 <+30>:	mov    eax,0x0
   0x0000555555554a0b <+35>:	mov    rdx,QWORD PTR [rbp-0x8]
   0x0000555555554a0f <+39>:	xor    rdx,QWORD PTR fs:0x28
   0x0000555555554a18 <+48>:	je     0x555555554a1f <mac()+55>
   0x0000555555554a1a <+50>:	call   0x555555554850 <__stack_chk_fail@plt>
   0x0000555555554a1f <+55>:	leave  
   0x0000555555554a20 <+56>:	ret    
End of assembler dump.gdb中对栈进行了检查

用基本数据类型接收时:mac函数执行,将临时变量num的地址存入rax寄存器中作为返回值,函数返回后在main函数中取出该地址的值存入变量i中

用引用接收是:mac函数执行,将临时变量num的地址存入rax寄存器中作为返回值,函数返回后在main函数直接将该地址取出存入引用变量当中,之后一系列操作均通过引用变量中保存的地址值来完成,若之后调用一些函数执行,则有可能会覆盖之前mac函数的堆栈,导致数据错误,并且当mac函数执行结束返回后该调用堆栈在系统中已经处于回收状态,是不可用的。

局部类
先看一个不用引用作为函数返回值的函数
class Struct{
	public:
	int a,b,c,d;
	int aa[10];
};

Struct Smac()
{
	Struct test;
	test.a=1;
	test.b=2;
	test.c=3;
	test.d=4;
	return test;
}


int main()
{
	Struct p=Smac();
	return 0;
}

函数返回时会进行内存复制,详细过程会在后续介绍

引用作为函数返回值
//程序是错误的
Struct& Smac()
{
	Struct test;
	test.a=1;
	test.b=2;
	test.c=3;
	test.d=4;
	return test;
}

int main()
{
	Struct p=Smac();
	Struct& pp=Smac();
	return 0;
}

asm:
Dump of assembler code for function Smac():
   0x00005555555547aa <+0>:	push   rbp
   0x00005555555547ab <+1>:	mov    rbp,rsp
   0x00005555555547ae <+4>:	sub    rsp,0x40
   0x00005555555547b2 <+8>:	mov    rax,QWORD PTR fs:0x28
   0x00005555555547bb <+17>:	mov    QWORD PTR [rbp-0x8],rax
   0x00005555555547bf <+21>:	xor    eax,eax
   0x00005555555547c1 <+23>:	mov    DWORD PTR [rbp-0x40],0x1
   0x00005555555547c8 <+30>:	mov    DWORD PTR [rbp-0x3c],0x2
   0x00005555555547cf <+37>:	mov    DWORD PTR [rbp-0x38],0x3
   0x00005555555547d6 <+44>:	mov    DWORD PTR [rbp-0x34],0x4
   0x00005555555547dd <+51>:	mov    eax,0x0//将0地址放入了返回值,访问时会出现异常,导致程序崩溃
   0x00005555555547e2 <+56>:	mov    rdx,QWORD PTR [rbp-0x8]
   0x00005555555547e6 <+60>:	xor    rdx,QWORD PTR fs:0x28
   0x00005555555547ef <+69>:	je     0x5555555547f6 <Smac()+76>
   0x00005555555547f1 <+71>:	call   0x555555554670 <__stack_chk_fail@plt>
=> 0x00005555555547f6 <+76>:	leave  
   0x00005555555547f7 <+77>:	ret    
End of assembler dump.
返回堆中数据
仅返回引用
class Struct{
	public:
	int a,b,c,d;
	int aa[10];
};
Struct& Smac()
{
	Struct *test=new Struct;
	test->a=1;
	return *test;
}
int main()
{
	Struct p=Smac();
	Struct& pp=Smac();
	return 0;
}

asm:
Dump of assembler code for function main():
...
=> 0x0000555555554828 <+8>:	mov    rax,QWORD PTR fs:0x28
   0x0000555555554831 <+17>:	mov    QWORD PTR [rbp-0x8],rax
   0x0000555555554835 <+21>:	xor    eax,eax
   0x0000555555554837 <+23>:	call   0x5555555547fa <Smac()>
   0x000055555555483c <+28>:	mov    rcx,rax//得到分配变量的地址,而后进行一系列内存复制操作
   0x000055555555483f <+31>:	mov    rax,QWORD PTR [rcx]
   0x0000555555554842 <+34>:	mov    rdx,QWORD PTR [rcx+0x8]
   0x0000555555554846 <+38>:	mov    QWORD PTR [rbp-0x40],rax
   0x000055555555484a <+42>:	mov    QWORD PTR [rbp-0x38],rdx
   0x000055555555484e <+46>:	mov    rax,QWORD PTR [rcx+0x10]
   0x0000555555554852 <+50>:	mov    rdx,QWORD PTR [rcx+0x18]
   0x0000555555554856 <+54>:	mov    QWORD PTR [rbp-0x30],rax
   0x000055555555485a <+58>:	mov    QWORD PTR [rbp-0x28],rdx
   0x000055555555485e <+62>:	mov    rax,QWORD PTR [rcx+0x20]
   0x0000555555554862 <+66>:	mov    rdx,QWORD PTR [rcx+0x28]
   0x0000555555554866 <+70>:	mov    QWORD PTR [rbp-0x20],rax
   0x000055555555486a <+74>:	mov    QWORD PTR [rbp-0x18],rdx
   0x000055555555486e <+78>:	mov    rax,QWORD PTR [rcx+0x30]
   0x0000555555554872 <+82>:	mov    QWORD PTR [rbp-0x10],rax
   0x0000555555554876 <+86>:	call   0x5555555547fa <Smac()>
   0x000055555555487b <+91>:	mov    QWORD PTR [rbp-0x48],rax
   0x000055555555487f <+95>:	 mov    eax,0x0
   0x0000555555554884 <+100>:	mov    rdx,QWORD PTR [rbp-0x8]
   0x0000555555554888 <+104>:	xor    rdx,QWORD PTR fs:0x28
   0x0000555555554891 <+113>:	je     0x555555554898 <main()+120>
   0x0000555555554893 <+115>:	call   0x5555555546c0 <__stack_chk_fail@plt>
   0x0000555555554898 <+120>:	leave  
   0x0000555555554899 <+121>:	ret    
End of assembler dump.

 Dump of assembler code for function Smac():
=> 0x00005555555547fa <+0>:	push   rbp
   0x00005555555547fb <+1>:	mov    rbp,rsp
   0x00005555555547fe <+4>:	sub    rsp,0x10
   0x0000555555554802 <+8>:	mov    edi,0x38
   0x0000555555554807 <+13>:	call   0x5555555546b0 <_Znwm@plt>
   0x000055555555480c <+18>:	mov    QWORD PTR [rbp-0x8],rax
   0x0000555555554810 <+22>:	mov    rax,QWORD PTR [rbp-0x8]
   0x0000555555554814 <+26>:	mov    DWORD PTR [rax],0x1
   0x000055555555481a <+32>:	mov    rax,QWORD PTR [rbp-0x8]
   0x000055555555481e <+36>:	leave  
   0x000055555555481f <+37>:	ret    
End of assembler dump.

当使用普通变量接收函数返回值时,传出分配变量的地址,而后使用该地址进行内存复制

当使用引用变量时,直接将传出的地址存入即可

指针引用
int main()
{
	int i=0;
	int *p=&i;
	int*& pp=p;
	int num=*pp;
	return 0;
}

asm:
Dump of assembler code for function main():
   0x00005555555547aa <+0>:	push   rbp
   0x00005555555547ab <+1>:	mov    rbp,rsp
   0x00005555555547ae <+4>:	sub    rsp,0x20
   0x00005555555547b2 <+8>:	mov    rax,QWORD PTR fs:0x28
   0x00005555555547bb <+17>:	mov    QWORD PTR [rbp-0x8],rax
   0x00005555555547bf <+21>:	xor    eax,eax
   0x00005555555547c1 <+23>:	mov    DWORD PTR [rbp-0x20],0x0
   0x00005555555547c8 <+30>:	lea    rax,[rbp-0x20]
   0x00005555555547cc <+34>:	mov    QWORD PTR [rbp-0x18],rax
=> 0x00005555555547d0 <+38>:	lea    rax,[rbp-0x18]
   0x00005555555547d4 <+42>:	mov    QWORD PTR [rbp-0x10],rax
   0x00005555555547d8 <+46>:	mov    rax,QWORD PTR [rbp-0x10]
   0x00005555555547dc <+50>:	mov    rax,QWORD PTR [rax]
   0x00005555555547df <+53>:	mov    eax,DWORD PTR [rax]
   0x00005555555547e1 <+55>:	mov    DWORD PTR [rbp-0x1c],eax
   0x00005555555547e4 <+58>:	mov    eax,0x0
   0x00005555555547e9 <+63>:	mov    rdx,QWORD PTR [rbp-0x8]
   0x00005555555547ed <+67>:	xor    rdx,QWORD PTR fs:0x28
   0x00005555555547f6 <+76>:	je     0x5555555547fd <main()+83>
   0x00005555555547f8 <+78>:	call   0x555555554670 <__stack_chk_fail@地址plt>
   0x00005555555547fd <+83>:	leave  
   0x00005555555547fe <+84>:	ret    
End of assembler dump.

指针的引用相当于一个二级指针,其内的值保存指针的地址

普通变量引用
int main()
{
	int i=0;
	int &p=i;
	return 0;
}

asm:
 0x00005555555547c8 <+30>:	lea    rax,[rbp-0x14] //i的地址
  0x00005555555547cc <+34>:	mov    QWORD PTR [rbp-0x10],rax//将地址存入p中

普通变量的引用相当于一个一级指针,保存引用变量的地址

引用作为函数参数
int mac(int &i)
{
	i=10;
	return 0;
}
int main()
{
	int num=10;
	mac(num);
	return 0;
}

asm:
Dump of assembler code for function main():
...
   0x00005555555547da <+23>:	mov    DWORD PTR [rbp-0xc],0xa
   0x00005555555547e1 <+30>:	lea    rax,[rbp-0xc]//获得参数地址
   0x00005555555547e5 <+34>:	mov    rdi,rax
   0x00005555555547e8 <+37>:	call   0x5555555547aa <mac(int&)>
...
   0x0000555555554807 <+68>:	ret    
End of assembler dump.
Dump of assembler code for function mac(int&):
...
   0x00005555555547ae <+4>:	mov    QWORD PTR [rbp-0x8],rdi
   0x00005555555547b2 <+8>:	mov    rax,QWORD PTR [rbp-0x8]
   0x00005555555547b6 <+12>:	mov    DWORD PTR [rax],0xa
...
   0x00005555555547c2 <+24>:	ret    
End of assembler dump.

传递参数时将变量地址保存到rdi寄存器中传参

右值引用

int main()
{
	int num=10;
	int *&&p=&num;
	return 0;
}

asm:
Dump of assembler code for function main():
...
   0x00005555555547c1 <+23>:	mov    DWORD PTR [rbp-0x1c],0xa
   0x00005555555547c8 <+30>:	lea    rax,[rbp-0x1c]//&num
   0x00005555555547cc <+34>:	mov    QWORD PTR [rbp-0x18],rax
   0x00005555555547d0 <+38>:	lea    rax,[rbp-0x18]
   0x00005555555547d4 <+42>:	mov    QWORD PTR [rbp-0x10],rax
...
   0x00005555555547f2 <+72>:	ret    
End of assembler dump.
 (gdb) p p
$21 = (int *&&) @0x7fffffffddd8: 0x7fffffffddd4
       cout<<p;输出为0x7fffffffddd4

右值引用,好比一个二级指针,但不同的是访问p可以直接获得num的地址,因而右值引用保存的是一个地址,为右值,不可更改.右值引用常用于类之间的拷贝、移动;使用右值引用可以减少重复内存拷贝,传递函数指针、普通函数参数等.如std::move(T&& t)).

复杂引用

函数指针的引用
作为函数返回值
int(*& fun(int (*&rp)(int,int)))(int, int)//最后的(int, int)为返回类型

返回一个函数指针的引用,函数指针指向的函数类型为int(&)(int,int),也是一个返回函数指针引用的函数,类型为int(&)(int,int)

作为函数参数
void fun(int(* & rp)(int,int))

一个int(*)(int,int)型指针的引用作为函数参数的函数

int (*&rp)(int,int))

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值