用汇编的眼光看C++(之拷贝、赋值函数)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/feixiaoxing/article/details/6772964


【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】


    拷贝构造函数和复制函数是类里面比较重要的两个函数。两者有什么区别呢?其实也很简单,我们可以举个例子,加入有这样一个类的定义:


 
 
  1. class apple
  2. {
  3. public:
  4. apple() { printf( "apple()!\n");}
  5. apple(apple& a) { printf( "copy apple()!\n");}
  6. apple& operator=(apple& a) { printf( "= apple()\n"); return * this;}
  7. ~apple() { printf( "~apple()!\n");}
  8. void print() const { return;}
  9. };

    那么我们在如下的函数里面进行调用的时候,调用的函数分别是哪些呢?


 
 
  1. void process()
  2. {
  3. apple a, c;
  4. apple b =a;
  5. c = b;
  6. }
    其实汇编的结果是这样的,大家可以一起看一下,自己尝试读一下。如果一次不是很明白,可以多读几次。


 
 
  1. 70: apple a, c;
  2. 0040127D lea ecx,[ebp-10h]
  3. 00401280 call @ILT+ 70(apple::apple) ( 0040104b)
  4. 00401285 mov dword ptr [ebp -4], 0
  5. 0040128C lea ecx,[ebp -14h]
  6. 0040128F call @ILT+ 70(apple::apple) ( 0040104b)
  7. 00401294 mov byte ptr [ebp -4], 1
  8. 71: apple b =a;
  9. 00401298 lea eax,[ebp-10h]
  10. 0040129B push eax
  11. 0040129C lea ecx,[ebp-18h]
  12. 0040129F call @ILT+ 50(apple::apple) ( 00401037)
  13. 004012A4 mov byte ptr [ebp -4], 2
  14. 72: c = b;
  15. 004012A8 lea ecx,[ebp-18h]
  16. 004012AB push ecx
  17. 004012AC lea ecx,[ebp-14h]
  18. 004012AF call @ILT+ 75(apple:: operator=) ( 00401050)
  19. 73: }
  20. 004012B4 mov byte ptr [ebp -4], 1
  21. 004012B8 lea ecx,[ebp -18h]
  22. 004012BB call @ILT+ 0(apple::~apple) ( 00401005)
  23. 004012C0 mov byte ptr [ebp -4], 0
  24. 004012C4 lea ecx,[ebp -14h]
  25. 004012C7 call @ILT+ 0(apple::~apple) ( 00401005)
  26. 004012CC mov dword ptr [ebp -4], 0FFFFFFFFh
  27. 004012D3 lea ecx,[ebp -10h]
  28. 004012D6 call @ILT+ 0(apple::~apple) ( 00401005)
  29. 004012DB mov ecx,dword ptr [ebp -0Ch]
  30. 004012DE mov dword ptr fs:[ 0],ecx
  31. 004012E5 pop edi
  32. 004012E6 pop esi
  33. 004012E7 pop ebx
  34. 004012E8 add esp, 58h
  35. 004012EB cmp ebp,esp
  36. 004012ED call __chkesp ( 004087c0)
  37. 004012F2 mov esp,ebp
  38. 004012F4 pop ebp
  39. 004012F5 ret
    代码有点长,大家可以一句一句来看,比如说就按照70、71、72、73分别查看对应的汇编代码:

    (1)70句: 我们看到函数做了两次函数调用,恰好就是apple的构造函数调用。这也正好对应着两个临时变量a和c,两个变量的地址分别是【ebp-10】和【ebp-14】,这里也可以看出整个类的大小就是4个字节,就是一块存放数据的普通内存。而构造函数之所以能和对应的内存绑定在一起,主要是因为ecx记录了内存的起始地址,这在C++编译中是十分关键的。我们看到的C++构造函数好像是没有绑定内存,实际上在VC里面已经做好了约定,ecx就是this指针,就是类的内存起始地址。有兴趣的同学看看G++编译的时候,采用的this指针是哪个寄存器保存的?(其实是eax)

    (2)71句:通过对应看到了eax记录了引用变量的地址,而ecx是ebp下面紧挨着四个字节。但是函数调用的地址和前面的缺省构造函数不太一样,所以我们大胆猜测,这里的构造函数这是拷贝构造函数,我们可以在调试的时候查看一下打印消息。

    (3)72句:0x4012AF语句已经清楚地告诉了我们,这里调用的函数就是operator=函数,这一部分是算术符重载的内容,我们在后面的博客会重点介绍。

    (4)73句: 前面我们讲过,析构函数在函数调用结束的时候被被自动调用,那么这里我们看到却是出现了三个调用?这三个变量正好是我们之前说的a、b、c三个变量。那么这三个变量调用的次序是怎样的呢?我们可以查看一下变量的地址,分别是【ebp-18h】、【ebp-14h】、【ebp-10h】,这正好和变量出现的顺序相反。所以我们看到,析构函数和构造函数是严格一一对应的,谁先出现,谁后析构。



【预告: 下面的博客我们会对构造、析构中出现的一些现象进行总结】

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值