函数返回引用类型 和 非引用类型究竟有什么不同呢?
先来个总结:非引用类型返回值的函数,返回的是一个新的临时对象。
分析见下图:
#include <iostream>
using namespace std;
class CText
{
public:
~CText()
{
cout<<"析构了"<<this<<endl;
}
};
CText& fRefer(CText &a)
{
return a;
}
CText fNoRefer(CText &a)
{
return a;
}
int main(int arge,char*argv[ ])
{
CText a;
cout<<"a的地址:"<<&a<<endl;
cout<<endl<<"------引用类型返回值------"<<endl;
a=fRefer(a);
cout<<endl<<"------非引用类型的返回值------"<<endl;
a=fNoRefer(a);
cout<<endl<<"------main结束------"<<endl;
return 0;
}
运行结果:
图1
如图,在调用非引用类型返回值函数的时候会多出了一个临时的对象。
多出的临时对象究竟有什么用呢?
我们用反汇编再深入看看内部运行过程。
如果对反汇编调试不太熟的朋友,请先看:《反汇编学习》
在看引用类型返回值函数之前先看看返回引用类型值的函数调用过程,如图:
解读:[ebp-10h]存放的是a对象的地址,把a作为参数压栈,然后调用fRefer。
fRefer内部:(只看红色部分)
图3
解读:[ebp+8]就是fRefer的参数a,直接将a返回。
接下来就看非引用类型返回值函数如图:
解读:将a对象的地址作为参数压入栈,然后调用fNoRefer。咦? 怎么压2个参数到栈里?一个是a对象的地址,另一个是?
这里,细心的读者可以发现另外一个参数正是图1里冒出来的临时对象。
fNoRefer函数的内部:(重点看红色框内部)
解读:[ebp+0Ch]是第一个参数即a对象的地址,[ebp+8]是第二个参数即临时产生的对象。将a赋值给临时对象,然后将临时对象返回。
回到图4,最后将返回值(即临时对象)赋值给a,然后销毁临时对象。
结论:非引用类型返回的是临时对象。
可见非引用类型的不但要多建一个临时对象,还会多出了不少的语句从而多消耗CPU性能。
如果还觉得晕晕的,我再举个例子:
#include <iostream>
using namespace std;
class CText
{
public:
void say()
{
cout<<"我是"<<this<<endl;
}
~CText()
{
cout<<"析构了"<<this<<endl;
}
};
CText& fRefer(CText& a)
{
return a;
}
CText fNoRefer(CText& a)
{
return a;
}
int main(int arge,char*argv[ ])
{
CText a;
cout<<"a的地址:"<<&a<<endl;
cout<<endl<<"------引用类型返回值------"<<endl;
fRefer(a).say();
cout<<endl<<"------非引用类型的返回值------"<<endl;
fNoRefer(a).say();
cout<<endl<<"------main结束------"<<endl;
return 0;
}
结果: