拷贝构造函数和复制函数是类里面比较重要的两个函数。两者有什么区别呢?其实也很简单,我们可以举个例子,加入有这样一个类的定义:
[cpp] view plaincopy
  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. };

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

[cpp] view plaincopy
  1. void process()
  2. {
  3. apple a, c;
  4. apple b =a;
  5. c = b;
  6. }

其实汇编的结果是这样的,大家可以一起看一下,自己尝试读一下。如果一次不是很明白,可以多读几次。

[cpp] view plaincopy
  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】,这正好和变量出现的顺序相反。所以我们看到,析构函数和构造函数是严格一一对应的,谁先出现,谁后析构。

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

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

  1. 用汇编的眼光看C++(之虚函数)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 虚函数是面向对象设计中的一个重要内容.它的出现使得我们只需要相同的接口函数,并可以得到不同的生 ...

  2. 用汇编的眼光看c++(之模板函数)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com]  如果说模板类定义的是一种数据类型,那么模板函数定义的就是一种函数.既然是函数,那么就有输入数 ...

  3. 用汇编的眼光看C++(之 总结篇)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 早在八月份的时候,就陆陆续续写了二十多篇用汇编语言看C++的博客内容.在此为了做一个概括,也为 ...

  4. 用汇编的眼光看C++(之退出流程)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 无论是在判断还是在循环的过程中,通常在遇到合适的条件的时候就会退出相应的模块.跳出模块运行的方 ...

  5. 用汇编的眼光看C++ (之x86汇编)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 说到用汇编的眼光看C++语言,那么怎么阅读汇编代码就成了我们需要解决的一个问题.其实,实话说, ...

  6. strcpy函数_错误更正(拷贝赋值函数的正确使用姿势)

    这是一篇对什么是C++的The Rule of Three的错误更正和详细说明. 阅读时间7分钟.难度⭐⭐⭐ 虽然上一篇文章的阅读量只有凄惨的两位数,但是怀着对小伙伴负责的目的,必须保证代码的正确性. ...

  7. 【C++】Big Five: 构造函数、拷贝构造函数、拷贝赋值函数、移动构造函数、析构函数

    前言 C++类的成员变量是否含有"指针类型"直接决定了"Big Five"函数(就是标题中的5个函数)的编写!有无指针类型"成员变量造成Big Fiv ...

  8. C++学习笔记day47-----C++98-继承中的构造函数,析构函数,拷贝构造函数,拷贝赋值函数,多重继承,虚继承

    继承中的构造函数 当通过一个子类创建一个新的对象时,编译器会根据子类在初始化表中指明的基类的初始化方式去调用基类相应的构造函数.如果子类的初始化表中,并没有指明基类的初始化方式,编译器将会调用基类的无 ...

  9. C++中的trivial和non-trivial构造/析构/拷贝/赋值函数及POD类型

    在侯捷的<STL源码剖析>里提到trivial和non-trivial及POD类型,相关知识整理如下. trivial意思是无意义,这个trivial和non-trivial是对类的四种函 ...

  10. 拷贝赋值函数、拷贝构造函数

    拷贝构造函数 也是构造函数的一种,常用来以另一对象为模板创建新对象.如果对象中没有指针,可以直接使用数据库自带的该函数,但有指针就需要自己构建,这是为了避免造成浅拷贝,使两个指针指向同一内存空间. 例 ...

最新文章

  1. php从数据库中读取特定的行
  2. 脚踏板USB接口与无线遥控连接方案论证
  3. 配置Windows server 2008 R2脱机加入域功能
  4. Protobuf3 + Netty4: 在socket上传输多种类型的protobuf数据
  5. Eclipse 安装插件(aptana、svn 、git、Java EE、JSHint)
  6. python phpstudy_GitHub - Writeup007/phpStudyBackDoor: phpStudy后门检测与利用工具,Python脚本,可一键 GetShell。...
  7. 【BZOJ】【2154】Crash的数字表格
  8. GPU(CUDA)学习日记(十三)------ CUDA内存简介
  9. R 调用 python
  10. 实现用户操作指引功能
  11. js数组去重的四种方式
  12. C++工作笔记-设计普通类的格式,实现简单工厂中接口的定义
  13. ASP.NET MVC程序播放H.264视频
  14. oracle subset-superset pairs,Oracle 字符集
  15. linux下intel安装教程,在64位Ubuntu下安装Intel Fortran 11
  16. HTML+CSS网页设计视频教程
  17. 哈工大车万翔教授:NLPer的核心竞争力是什么?
  18. QT项目--简易音乐播放器
  19. SpringCloud(三)了解了概念,现在来验证一下,玩个小案例
  20. 厦门大学麦嘉仪:统计学专业到微众银行风控岗!

热门文章

  1. android 语音通信,Android与PC间的语音通信
  2. 网页设计html最简单水印方法,前端canvas水印快速制作(附完整代码)
  3. java 枚举使用例子_Java枚举详解及使用实例(涵盖了所有典型用法)
  4. rabbitmq 取消消息_SpringBoot整合RabbitMQ实现延迟消息
  5. 华为手机怎么隐藏按键图标_华为手机隐藏技巧,一键简单设置,让沟通更加便捷...
  6. python连不上树莓派_Python实现树莓派WiFi断线自动重连
  7. 计算机微课应用报告书,【计算机专业论文】计算机专业教学中微课的应用(共4253字)...
  8. 状态机思路在嵌入式开发中的应用详解
  9. 24岁博士毕业,受聘211高校副教授,90后开挂背后是自律和坚持
  10. 程序员崩溃的40个瞬间!(动图)