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 ...
随机推荐
- iOS: 神奇的addSubView
看着addSubView, 本以为是添加多个对象, 但通过测试代码, 发现同一个对象在addSubView中只会添加一次. 想想, 视图对象是通过引用得到的. 在视图的子视图集中, 只保存一个相应的对 ...
- 转:实用 .htaccess 用法大全
原文来自于:http://www.techug.com/htaccess-snippets 这里收集的是各种实用的 .htaccess 代码片段,你能想到的用法几乎全在这里. 免责声明: 虽然将这些代 ...
- [BZOJ 1081] [SCOI2005] 超级格雷码 【找规律】
题目链接:BZOJ - 1081 备注:此题BZOJ上貌似没有 spj ,要把一般顺序的每个格雷码倒着输出...比如 0102 输出为 2010 题目分析 就是按照 Gray 码的生成方法写前几个出来 ...
- 【Java】数据库连接池技术
JDBC的问题 在程序中,我们经常要建立与数据库的连接,之后再关闭这个连接.我们知道,数据库连接对象的创建是比较消耗系统性能的,这些频繁的操作势必会消耗大量的系统资源.因此我们需要采用更高效的数据库访 ...
- .froxlor 玩起
其实,细想想, 这方面很有操作余地的哟.
- apk,task,android:process与android:sharedUserId的区别
apk一般占一个dalvik,一个进程,一个task.通过设置也可以多个进程,占多个task. task是一个activity的栈,其中"可能"含有来自多个App的activity ...
- 【HDOJ】2782 The Worm Turns
DFS. /* 2782 */ #include <iostream> #include <queue> #include <cstdio> #include &l ...
- poj3373
其实这道题只告诉了一个事当出现多个满足答案约束条件是,我们可以求一个再求一个,不要一下子全求完前两个条件怎么弄之前已经做过类似的了于是我们可以用记忆化搜索找出最小差异然后配合最小差异来剪枝,搜索出最小 ...
- 动态规划(树形DP):HDU 5834 Magic boy Bi Luo with his excited tree
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAA8UAAAJbCAIAAABCS6G8AAAgAElEQVR4nOy9fXQcxZ0uXH/hc8i5N+
- Atmospheric Scattering in Unity5
本次实践效果仅有Atmospheric Scattering和AA,并无其他post-processing,看到类似depth of field等的效果全部是Atmospheric Scatterin ...