- 论坛徽章:
- 0
|
不纠缠于语法的解释,看代码和汇编结果最直接。举下面这个小例子程序: (gcc -masm=hello -S main.cpp可以得到汇编代码)
#include<stdio.h>
int x=3;
int f1(){return x;}
int& f2(){return x;}
int main(){
int a=f1();
int y=f2();
y=4;//仍然有x=3
int&z=f2();
z=5;
printf("x=%d,y=%d",x,y);//z改变了x
return 0;
}
输出是什么呢? x=5,y=4
分析:
f2是个返回引用的函数,当且仅当int&z =f2()的时候才是真的返回引用,int y=f2()返回的仍然是一个值的拷贝
--------------------------------------------------------------------------------------------------------------------
f1和f2的定义:
.globl __Z2f1v
.def __Z2f1v; .scl 2; .type 32; .endef
__Z2f1v:
push ebp
mov ebp, esp
mov eax, DWORD PTR _x f1()返回一个值的拷贝
pop ebp
ret
.align 2
.globl __Z2f2v
.def __Z2f2v; .scl 2; .type 32; .endef
__Z2f2v:
push ebp
mov ebp, esp
mov eax, OFFSET FLAT:_x f2()返回的就是一个地址,不是值
pop ebp
ret
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
我们看一下main函数
_main:
push ebp
mov ebp, esp
sub esp, 40
and esp, -16
mov eax, 0
add eax, 15
add eax, 15
shr eax, 4
sal eax, 4
mov DWORD PTR [ebp-16], eax
mov eax, DWORD PTR [ebp-16]
call __alloca
call ___main
call __Z2f1v -> 调用f1(), 返回值放在eax
mov DWORD PTR [ebp-4], eax -> eax赋值给a
call __Z2f2v
mov eax, DWORD PTR [eax] -> 调用f2(), 返回x的值拷贝放在eax
mov DWORD PTR [ebp-8], eax -> eax赋值给y
mov DWORD PTR [ebp-8], 4 -> 立即数"4"赋值给y. y的改变不会改变x!!!!!!
call __Z2f2v
mov DWORD PTR [ebp-12], eax -> 调用f2(), 返回x的地址给z
mov eax, DWORD PTR [ebp-12] -> x的地址放入eax
mov DWORD PTR [eax], 5 -> 赋值5给eax指向的地址x
mov eax, DWORD PTR [ebp-8] //以下是printf的调用
mov DWORD PTR [esp+8], eax
mov eax, DWORD PTR _x
mov DWORD PTR [esp+4], eax
mov DWORD PTR [esp], OFFSET FLAT:LC0
call _printf
mov eax, 0
leave
ret
.def _printf; .scl 2; .type 32; .endef
结论:
我们生命了一个int& f()这样的函数,但是在使用的时候并没有int& z=f(),那么仍然是去返回了一个值的拷贝,如果是对象的话有调用了一个operator=拷贝构造函数。因此必须在使用的时候记住T& t=f()去得到函数返回的引用。
当然,如果f()返回的不是引用的话,T&t 得到当前调用堆栈上面的临时对象,不能在当前上下文之外引用,否则可能引起"未定义"的行为。
[ 本帖最后由 jeanlove 于 2009-2-27 13:12 编辑 ] |
|