c++中返回对象与返回引用的区别
这几天在做用C++做课程设计,对其返回对象的实现感到迷惑。
通过对汇编代码的分析,可以清楚的看到,直接返回引用和返回对象的区别到底是什么。
分析的程序如下
#include<cstdio>
class Node
{
public:
Node(int _num, char *_str):
num(_num), str(_str)
{
}
int getInt()
{
return num;
};
void setInt(int n)
{
num = n;
}
char* getStr()
{
return str;
}
private:
int num;
char *str;
};
Node node(,"good");
Node getNode1()
{
return node;
}
Node& getNode2()
{
return node;
}
int main()
{
Node node1 = getNode1();
printf("%d,%s",node1.getInt(),node1.getStr());
Node node2 = getNode2();
printf("%d,%s",node2.getInt(),node2.getStr());
;
}
有两个getNode函数,一个直接返回对象,一个返回对象的引用。
反汇编结果(采用MinGW编译器)
. ; Node getNode1() . public __Z8getNode1v . __Z8getNode1v proc near ; CODE XREF: _main+Fp . push ebp . mov ebp, esp . mov eax, ds:_node.num ;将成员num的值放到eax寄存器 . mov edx, ds:_node.str ;将成员str的值放到eda寄存器 .text:0040157E pop ebp .text:0040157F retn .text:0040157F __Z8getNode1v endp .text:0040157F . . ; =============== S U B R O U T I N E ======================================= . . ; Attributes: bp-based frame . . ; Node *getNode2() . public __Z8getNode2v . __Z8getNode2v proc near ; CODE XREF: _main+48p . push ebp . mov ebp, esp . mov eax, offset _node ;将node对象的地址值放到eax寄存器 . pop ebp . retn . __Z8getNode2v endp . .text:0040158A .text:0040158A ; =============== S U B R O U T I N E ======================================= .text:0040158A .text:0040158A ; Attributes: bp-based frame .text:0040158A .text:0040158A ; int main() .text:0040158A public _main .text:0040158A _main proc near ; CODE XREF: ___tmainCRTStartup+25Dp .text:0040158A . .text:0040158A .text:0040158A push ebp .text:0040158B mov ebp, esp .text:0040158D push ebx .text:0040158E and esp, 0FFFFFFF0h . sub esp, 20h ;开辟栈空间 . call ___main . call __Z8getNode1v ; getNode1(void) .text:0040159E mov [esp+18h], eax ;取出成员num的值放到栈中 .text:004015A2 mov [esp+1Ch], edx ;去除成员str的值放到栈中 .text:004015A6 lea eax, [esp+18h] ;栈中对象的首地址存取eax寄存器,当作.text:004015AC处函数调用的参数 .text:004015AA mov ecx, eax .text:004015AC call __ZN4Node6getStrEv ; Node::getStr(void) .text:004015B1 mov ebx, eax .text:004015B3 lea eax, [esp+18h] ;栈中对象的首地址存取eax寄存器,当作.text:004015B9处函数调用的参数 .text:004015B7 mov ecx, eax .text:004015B9 call __ZN4Node6getIntEv ; Node::getInt(void) .], ebx .], eax .text:004015C6 mov dword ptr [esp], offset __format ; this .text:004015CD call __Z6printfPKcz ; printf(char const*,...) .text:004015D2 call __Z8getNode2v ; getNode2(void) .] ;返回值为Node对象的首地址,存放在eax寄存器中,此处取其成员str的值 .text:004015DA mov eax, [eax] ;返回值为Node对象的首地址,存放在eax寄存器中,此处取其成员num的值 .text:004015DC mov [esp+10h], eax ;将Node对象首地址放到栈中(esp+10h处) .text:004015E0 mov [esp+14h], edx .text:004015E4 lea eax, [esp+10h] ;将栈中esp+10h处存放的Node对象首地址放到eax中,为函数调用的参数 .text:004015E8 mov ecx, eax .text:004015EA call __ZN4Node6getStrEv ; Node::getStr(void) .text:004015EF mov ebx, eax ;返回的字符串首地址存在eax寄存器中,此处复制到ebx寄存器中 .text:004015F1 lea eax, [esp+10h] ;将栈中esp+10h处存放的Node对象首地址放到eax中,为函数调用的参数 .text:004015F5 mov ecx, eax .text:004015F7 call __ZN4Node6getIntEv ; Node::getInt(void) .], ebx . ], eax . mov dword ptr [esp], offset __format ; __format .text:0040160B call __Z6printfPKcz ; printf(char const*,...) 此函数参数用栈传递 esp+8为字符串首地址 esp+4为num . . mov ebx, [ebp+var_4] . leave . retn . _main endp
在汇编代码中,可以清楚的看到函数返回引用实际是返回的一个指针,直接返回对象则会把对象中的数据全部复制(此处只有一个int和一个char指针,所以用了两个寄存器,如果数据项很多则会使用栈传递)。
Node node2 = getNode2(); //此函数返回对象引用
而对于上边这句,由于node2为一个存在栈中的对象,所以会根据getNode1函数返回的指针将其指向对象所有的数据全部拷贝到栈中对象的空间内。
对于
Node node1 = getNode1();//此函数直接返回对象
是将此函数的返回数据全部拷贝到栈中,返回的数据包含原对象的所有数据。
综上
c++中返回对象引用实际是返回的对象指针,直接返回对象会把对象的数据全部拷贝一遍(拷贝到寄存器或栈中)。
而对于将返回值赋值给一个对象时,如果函数返回的是引用,则会根据指针将所有数据拷贝过去,如果返回的是对象,会把返回的对象的数据(可能在寄存器中,或栈中)再拷贝到需赋值的对象中去。
所以
Node node = getNode()
如果函数返回对象引用,对象的数据会被拷贝一次,如果直接返回对象,则会被拷贝两次。
c++中返回对象与返回引用的区别的更多相关文章
- C++返回对象和返回引用
我们发现,在C++中,有些成员函数返回的是对象,而有些函数返回的又是引用. 返回对象和返回引用的最主要的区别就是函数原型和函数头. Car run(const Car &) //返回对 ...
- [转]ThinkPHP中实例化对象M()和D()的区别,select和find的区别
1.ThinkPHP中实例化对象M()和D()的区别 在实例化的过程中,经常使用D方法和M方法,这两个方法的区别在于M方法实例化模型无需用户为每个数据表定义模型类,如果D方法没有找到定义的模型类,则会 ...
- ThinkPHP中实例化对象M()和D()的区别,select和find的区别
原文:ThinkPHP中实例化对象M()和D()的区别,select和find的区别 1.ThinkPHP中实例化对象M()和D()的区别 在实例化的过程中,经常使用D方法和M方法,这两个方法的区别在 ...
- ThinkPHP中实例化对象M()和D()的区别
ThinkPHP中实例化对象M()和D()的区别 ThinkPHP中实例化对象M()和D()的区别?ThinkPHP如何实例化对象?在实例化的过程中,经常使用D方法和M方法,这两个方法的区别在于M方法 ...
- C#中Monitor对象与Lock关键字的区别分析
这篇文章主要介绍了C#中Monitor对象与Lock关键字的区别,需要的朋友可以参考下 Monitor对象 1.Monitor.Enter(object)方法是获取 锁,Monitor.Exit(ob ...
- (C/C++学习)21.C++中返回引用和返回对象以及传引用和传对象问题
说明:在学习和编写C++代码时,经常会遇到这样的问题:一个带返回值的函数,到底应该返回值呢,还是应该返回引用呢:在传递参数的时候,是应该传递参数的引用呢,还是应该传值呢?请看下面代码: void my ...
- [转] C++中临时对象及返回值优化
http://www.cnblogs.com/xkfz007/articles/2506022.html 什么是临时对象? C++真正的临时对象是不可见的匿名对象,不会出现在你的源码中,但是程序在运行 ...
- 转:C++中临时对象及返回值优化
http://www.cnblogs.com/xkfz007/articles/2506022.html 什么是临时对象? C++真正的临时对象是不可见的匿名对象,不会出现在你的源码中,但是程序在运行 ...
- Vue中data返回对象和返回值的区别
速记:粗浅的理解是,事件的结果是影响单个组件还是多个组件.因为大部分组件是要共享的,但他们的data是私有的,所以每个组件都要return一个新的data对象 返回对象的时候 <!DOCTYPE ...
随机推荐
- js中对象调用对象中的方法
var o = {a:"abc", b:{ c:function(param){ alert(this.a); //这里的this指向的不是o而是b,所以this是没有a属性的,这 ...
- EQueue 2.3.2
EQueue 2.3.2版本发布(支持高可用) 前言 前段时间针对EQueue的完善终于告一段落了,实在值得庆祝,自己的付出和坚持总算有了成果.这次新版本主要为EQueue实现了集群功能,基本实现了B ...
- System.Reflection.Assembly.GetEntryAssembly()获取的为当前已加载的程序集
今天在使用System.Reflection.Assembly.GetEntryAssembly()获取程序集时,发现获取的程序集不全.原来是因为C#的程序集为延迟加载,此方法只获取当前已加载的,未加 ...
- 各大Oj平台介绍[转]
1.题库与网站资源题库-在线提交系统(Online Judge)简介 下面是几个比较大的在线提交系统(OnlineJudge)里面有大量历年的竞赛题目,注册一个ID,然后用自己熟悉的语言(一般有P ...
- 《agile java》First : 起步 + 章节练习题
第一章节:起步 1.创建简单Java类2.创建测试类3.使用JUnit4.学习构造函数5.重构代码 涉及知识:TDD.UML TDD: Test Driven Development, 测试驱动开发. ...
- BZOJ 2005 能量采集
Description 栋栋有一块长方形的地,他在地上种了一种能量植物,这种植物可以采集太阳光的能量.在这些植物采集能量后,栋栋再使用一个能量汇集机器把这些植物采集到的能量汇集到一起. 栋栋的植物种得 ...
- BZOJ 3992 序列统计
Description 小C有一个集合\(S\),里面的元素都是小于\(M\)的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为\(N\)的数列,数列中的每个数都属于集合\(S\). 小C用 ...
- PHP 如何安全的使用 MySQL ?
大多数 PHP 程序员对 MySQL 肯定不陌生,至于各种 MySQL 函数的用法在开发手册和 w3school 这类网站上也有很多介绍.但是,你所用的写法真的安全吗?面对越来越猖獗的黑客攻击,SQL ...
- 自定义JSON配置器
比如要写个专门处理float类型的方法,然后注册到JSON配置器中,具体如下: 配置器代码如下: import java.math.RoundingMode; import java.text.Num ...
- windows/NBTSTAT,linux/nmblookup命令详解,查询NetBIOS名
NBTSTAT命令详解 请问: Linux下有没有和nbtstat一样的命令,用 nmblookup -A ip 可以 nbstat命令主要用于查看当前基于netbios的tcp/ip连接状态,通过该 ...