C++愤恨者札记2——函数返回值为类对象

C++愤恨者札记2——函数返回值为类对象
    为避免冗余代码,程序使用Release配置编译,但要把/Od选项打上,否则编译器优化,会使用代码很难懂。
    当函数返回值是基本的数据类型(如,int,char)时,会把返回结果放在eax上,这样函数调用者就可以通过eax获得函数返回结果了。但如果返回值是一个类对象呢?eax根本不够用了。

实验源码:
class Node
{
public:
    Node(){}
    //Node(Node& n){}
    int data1;
    int data2;
    int data3;
};

Node Fn()
{
    Node n;
    n.data1 = 100;    

    return n;
}

void main()
{
    Fn();
}


----------------------------------------------------------------------
    调用者处理过程。main将会在栈上为Fn分配临时空间,大小为其返回对象尺寸,代码没有优化的前提下,Fn出现一次会分配一份,出现两次则两份,依此类推。可以把"Fn ();"复制几次试试。调用Fn时,为Fn分配的临时空间的地址将压栈,Fn内部将使用这个地址来存放返回结果。

hello!main:
012a1040 55              push    ebp
012a1041 8bec            mov     ebp,esp
012a1043 83ec0c          sub     esp,0Ch	;开辟临时空间,sizeof(Node)大小就是12,即0CH

012a1046 8d45f4          lea     eax,[ebp-0Ch]
012a1049 50              push    eax		;压入临时空间地址
012a104a e8c1ffffff      call    hello!Fn (012a1010)
012a104f 83c404          add     esp,4

012a1052 33c0            xor     eax,eax

012a1054 8be5            mov     esp,ebp
012a1056 5d              pop     ebp


----------------------------------------------------------------------
    无拷贝构造函数的情况下,Fn的反汇编结果。Fn会把结果拷贝到临时空间中去,而这个临时空间的地址在main调用Fn时,已经压入栈了。

hello!Fn [e:\hello\hello\hello.cpp @ 29]:
29 012a1010 55              push    ebp
29 012a1011 8bec            mov     ebp,esp
29 012a1013 83ec0c          sub     esp,0Ch	;分配内存

30 012a1016 8d4df4          lea     ecx,[ebp-0Ch]		;无参构造函数的this指针
30 012a1019 e8e2ffffff      call    hello!Node::Node (012a1000)	;无参构造函数调用

31 012a101e c745f464000000  mov     dword ptr [ebp-0Ch],64h		;n.data1 = 100;

33 012a1025 8b4508          mov     eax,dword ptr [ebp+8]		;调用Fn时压入的临时空间地址

33 012a1028 8b4df4          mov     ecx,dword ptr [ebp-0Ch]		;复制第一个成员data1
33 012a102b 8908            mov     dword ptr [eax],ecx

33 012a102d 8b55f8          mov     edx,dword ptr [ebp-8]		;复制第二个成员data2
33 012a1030 895004          mov     dword ptr [eax+4],edx

33 012a1033 8b4dfc          mov     ecx,dword ptr [ebp-4]		;复制data3,如果成员很多
33 012a1036 894808          mov     dword ptr [eax+8],ecx		;则会使用rep movs来复制

33 012a1039 8b4508          mov     eax,dword ptr [ebp+8]

34 012a103c 8be5            mov     esp,ebp
34 012a103e 5d              pop     ebp
34 012a103f c3              ret


----------------------------------------------------------------------

    加上拷贝构造函数后(去掉注释后),Fn把复制工作交给拷贝构造函数去做,临时空间地址也交给它。所以被调用的拷贝构造函数将影响到main中分配的临时空间,从而实现了数据的传递,即类对象的返回。

hello!Fn:
01381020 55              push    ebp
01381021 8bec            mov     ebp,esp
01381023 83ec0c          sub     esp,0Ch	;分配内存

01381026 8d4df4          lea     ecx,[ebp-0Ch]
01381029 e8d2ffffff      call    hello!Node::Node (01381000)	;构造函数

0138102e c745f464000000  mov     dword ptr [ebp-0Ch],64h	;n.data1 = 100;

01381035 8d45f4          lea     eax,[ebp-0Ch]
01381038 50              push    eax
01381039 8b4d08          mov     ecx,dword ptr [ebp+8]		;临时空间地址,作为this指针
0138103c e8cfffffff      call    hello!Node::Node (01381010)	;调用拷贝构造函数

01381041 8b4508          mov     eax,dword ptr [ebp+8]
01381044 8be5            mov     esp,ebp
01381046 5d              pop     ebp
01381047 c3              ret



©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页