【编程篇】C++11系列之——临时对象分析
如下代码:
- /**********************************************/
- class CStudent;
- CStudent GetStudent()
- {
- CStudent loc_stu;
- return loc_stu;
- }
- int main()
- {
- CStudent stu = GetStudent();
- }
- /**********************************************/
来看一下main函数中调用GetStudent()的汇编实现:
aaarticlea/png;base64,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" alt="" />
看上去,GetStudent()是无参函数,可是为什么在call之前push了一个参数到堆栈里呢?并且call完之后还add esp, 4来使堆栈平衡。
这个调用是这么实现的:
首先,在main函数中,stu是作为局部变量存在的,因为是个对象,会调用构造函数。
但是请注意!!!!:这里并不会在main函数中调用构造函数来构造stu,而是仅仅为stu预留了空间sizeof(CStudent)大小,并将这个空间的地址通过
mov eax, address
push eax
传递给了GetStudent()。
在GetStudent()内部定义了它的局部变量loc_stu,GetStudent()内部构造了它,在返回的时候,通过 <拷贝构造函数> 拷贝到前面提到的那个通过eax传递的隐含的参数。
总结就是说虽然stu在main里面定义,但其内存区域的内容是由GetStudent()完成的。这里需要注意的是这种调用方式,因为返回的是个对象,所以做法是调用者提前准备好一个对象空间,然后把地址告诉被调用者,被调用者得到这个地址后对其赋值,从而完成对象的返回。我姑且将这种调用方式称之为__robjcall:返回对象调用方式!呵呵
注意!!!
如果main函数改成下面这样:
- /***************************************************************************/
- int main()
- {
- //CStudent stu = GetStudent(); 原来的写法
- CStudent stu;
- stu = GetStudent();
- }
- /***************************************************************************/
这样先定义再赋值则大为不同!!!
stu此时作为main函数的局部变量则会调用构造函数进行初始化。另外调用GetStudent()时和上面一样,因为返回的是对象,则需要一个对象的地址,这里并不是将stu的地址交给它,因为stu已经构造好了,不能交给别的函数随意处理。而是会产生一个临时的匿名对象!!!
这个临时的匿名对象将代替之前第一种写法的做法,将自己地址交给GetStudent(),完成自己
内存的赋值。最后,通过stu的赋值操作符operator=将临时对象的值交给stu自己。再然后,临时对象完成自己的使命,立即析构,而不会等到main函数退出时。当然这个匿名的临时对象同样作为main函数的局部变量,在main函数栈帧建立时就预留了空间,这是编译器在编译的时候发现了需要一个临时对象来完成任务所以为其预留了位置。
所以,由上看出,第二种写法将增加临时对象的开销,还有进行赋值操作的开销。
- /***************************************************************************/
- class Array
- {
- public:
- Array(int l) //构造函数
- {
- pData = new int[l];
- len = l;
- }
- ~Array() //析构函数
- {
- delete pData;
- len = ;
- }
- Array(const Array& other) //拷贝构造函数
- {
- pData = new int[other.len];
- memcpy(pData, other.pData, other.len);
- len = other.len;
- }
- Array& operator=(const Array& other) //赋值操作符
- {
- pData = new int[other.len];
- memcpy(pData, other.pData, other.len);
- len = other.len;
- return *this;
- }
- private:
- int* pData;
- int len;
- };
- /***************************************************************************/
在C++11中为了解决这个问题,引入了右值引用和move语意!
C++98规定了左值引用,如
int a;
int &b = a;
这里,b作为一个引用,引用了变量a的值,这里a是一个左值。
C++11引入了右值引用:
int &&m = 5;
这里会将5转换为一个临时对象(int型变量),然后m引用这个临时对象。
既然是右值引用,只可以引用临时对象——即右值!
这样,在C++11里,类引入了转移构造函数和转移赋值操作符,如下:
- /***************************************************************************/
- class Array
- {
- public:
- Array(int l); //构造函数
- ~Array(); //析构函数
- Array(const Array& other); //拷贝构造函数
- Array& operator=(const Array& other); //赋值操作符
- Array(Array&& other) //转移构造函数
- {
- pData = other.pData;
- len = other.len;
- /*将资源转移过来,避免资源拷贝*/
- other.pData = NULL;
- other.len = ;
- }
- Array& operator=(Array&& other) //转移赋值操作符
- {
- pData = other.pData;
- len = other.len;
- /*将资源转移过来,避免资源拷贝*/
- other.pData = NULL;
- other.len = ;
- return *this;
- }
- private:
- int* pData;
- int len;
- };
- Arrar GetArray()
- {
- Array loc_num();
- /*some operation*/
- return loc_num;
- }
- int main()
- {
- Array num();
- num = GetArray();
- }
- /***************************************************************************/
这样,当main函数中调用GetArray()时,虽然会有一个临时匿名对象产生(前面说了,用于GetArray填充返回值用),但这里在将临时对象的内容赋值给局部对象num时,将自动识别为右值赋值,不会调用原始赋值函数Array& operator=(const Array& other);转而调用转移赋值函数Array& operator=(const Array&& other);不会进行内存二次分配,从而节省开销。
【编程篇】C++11系列之——临时对象分析的更多相关文章
- 11.C++-临时对象分析
首先来参考以下代码: #include <stdio.h> class Test { int mi; public: Test(int i) { mi = i; } Test() { Te ...
- 3.1Python数据处理篇之Numpy系列(一)---ndarray对象的属性与numpy的数据类型
目录 目录 (一)简单的数组创建 1.numpy的介绍: 2.numpy的数组对象ndarray: 3.np.array(list/tuple)创建数组: (二)ndarray对象的属性 1.五个常用 ...
- 4.7Python数据处理篇之Matplotlib系列(七)---matplotlib原理分析
目录 目录 前言 (一)总框架分析 (二)函数式的绘图 1.说明: 2.函数绘图的缺优点 3.绘图类的函数 4.操作类的函数 5.例子: (三)面向对象式的绘图 1.基本概念 2.基本对象 3.面向对 ...
- 如何用ABP框架快速完成项目(面向项目交付编程面向客户编程篇)(1) - 目录
昨天发表了<如何用ABP框架快速完成项目 - 自动化测试 - 前端angular e2e protractor>后,大家十分热情,几个小时内就收到了不少问题,包括: 对于ui自动化测试这方 ...
- PHP求职宝典系列——PHP Web 编程篇
PHP Web 编程篇 form表单 1.简述 POST 和 GET 传输的最大容量分别是多少? GET 方法提交的表单数据被附加到 URL 上,并作为URL 的一部分发送到服务器端. URL 的长度 ...
- Java并发编程锁系列之ReentrantLock对象总结
Java并发编程锁系列之ReentrantLock对象总结 在Java并发编程中,根据不同维度来区分锁的话,锁可以分为十五种.ReentranckLock就是其中的多个分类. 本文主要内容:重入锁理解 ...
- JSP第四篇【EL表达式介绍、获取各类数据、11个内置对象、执行运算、回显数据、自定义函数、fn方法库】
什么是EL表达式? 表达式语言(Expression Language,EL),EL表达式是用"${}"括起来的脚本,用来更方便的读取对象! EL表达式主要用来读取数据,进行内容的 ...
- day7_直播_网络编程篇(元昊老师著)
网络编程篇计算机网络: 多台独立的计算机用网络通信设备连接起来的网络.实现资源共享和数据传递. 比如,我们之前的学过的知识可以将D盘的一个文件传到C盘,但如果你想从你的电脑传一个文件到我的电脑上目前是 ...
- SAP接口编程 之 JCo3.0系列(01):JCoDestination
SAP接口编程 之 JCo3.0系列(01):JCoDestination 字数2101 阅读103 评论0 喜欢0 JCo3.0是Java语言与ABAP语言双向通讯的中间件.与之前1.0/2.0相比 ...
随机推荐
- centos6.5安装oracle11g_2
centos7安装oracle数据库不成功,换成centos6.5安装,可以安装成功,记录一下 安装系统时,主机名如果不是用localhost,安装成功后,要用主机名和ip做映射,修改/etc/hos ...
- github提交代码时,报permission denied publickey
在像github提交代码时,报permission denied publickey. 查找了一下,可能是因为github的key失效了. 按照以下步骤,重新生成key. ssh-keygen 一路默 ...
- codevs2800 送外卖
题目描述 Description 有一个送外卖的,他手上有n份订单,他要把n份东西,分别送达n个不同的客户的手上.n个不同的客户分别在1~n个编号的城市中.送外卖的从0号城市出发,然后n个城市都要走一 ...
- 微信安卓版下载 Android微信各版本列表
前面ytkah弄了一个iso微信各版本列表,现在就来整一个微信 for Android各版本列表,方便大伙下载.每个版本都放出一些新的功能或修复相关错误,详情可以点击下面的版本链接进行查看.资源收集于 ...
- jquery 扩展插件方法
分析插件jquery.countdown.js (function($) { $.fn.countdown = function(options) { // default options var d ...
- hadoop 2.6 centos 7.1 下的一些操作
开启hdfs: start-dfs.sh 开启yarn: start-yarn.sh 查看hdfs:http://ip:50070/ 查看RM:http://ip:8088/
- HDU 3622 Bomb Game
Description \(n\) 个炸弹,每个炸弹有两个放置点,可以任选一个,问你最大的半径是多少. Sol 二分+2-SAT+Tarjan. 首先二分一下答案.然后就成了一个2-SAT问题. 建模 ...
- quartz集群报错but has failed to stop it. This is very likely to create a memory leak.
quartz集群报错but has failed to stop it. This is very likely to create a memory leak. 在一台配置1核2G内存的阿里云服务器 ...
- javascript小技巧
事件源对象 event.srcElement.tagName event.srcElement.type 捕获释放 event.srcElement.setCapture(); event.srcE ...
- LeetCode 26 Remove Duplicates from Sorted Array
Problem: Given a sorted array, remove the duplicates in place such that each element appear only onc ...