目录
当n是全局变量:
- int Count1() {
- static int n = 0;
- n++;
- //....
- return n;
- }
-
- int main() {
- int ret = Count1();
- cout << ret << endl;
- return 0;
- }

调用Count1时会为其建立栈帧, 因为变量n是全局变量,n不在栈区而在静态区,之后Count1函数结束,栈帧被销毁,但n的生命周期是全局的,执行return n时n还在,这样ret就接收到函数的返回值了。
而当n是局部变量时:
- int Count2() {
- int n = 0; //局部变量
- n++;
- //....
- return n;
- }
- int main() {
- int ret2 = Count2();
- cout << ret2 << endl;
- return 0;
- }

因为n是局部变量,当函数即将结束时,n会被销毁,此时,执行return n会让n在栈帧外开辟一个临时变量,里面存放n的值(拷贝),而ret指向Count2的返回值,又会再进行对n的临时变量进行接收(再拷贝一次)。
所以值传递效率低:会进行两次拷贝,时间效率较低。
- //引用返回
- int& Count3() {
- static int n = 0;
- n++;
- //....
- return n;
- }
-
- int main() {
- int ret = Count3();
- cout << ret << endl;
- return 0;
- }

用ret接收Count3的引用返回时,n会为其开辟临时变量,但这个变量并不开辟空间,所以整个过程只进行了一次拷贝,效率高。
- int& Count4() {
- int n = 0;
- n++;
- //....
- return n;
- }
- int main() {
- int ret = Count4();
- cout << ret << endl;
- return 0;
- }

n为局部变量,函数栈帧被销毁时,n也没了,所以返回n时,使用临时变量(n的别名)会越界,ret属于非法访问n变量(相当于野指针的访问),虽然不会报错,但是属于非法操作。
n被销毁,这块空间还给了操作系统,空间还在,也可以再进行访问,只不过是非法访问而已,但之前存储的数据是不被保护的,空间可能会分配给其他人,那么这块空间原有的数据也会被覆盖。 就好比住酒店房间时,我们放了很多东西在房间,游玩了几天后,退房时将房卡还给了酒店工作人员,离开酒店后才想起当时自己的毛巾落在了酒店,但那个房间已经不属于我了,这时有两种情况:
一.我偷偷回到房间,毛巾还在,这时房间还未分配给其他人;
二.我回来的时候,房间已经被保洁阿姨打扫过了(门还开着),我悄悄进去发现毛巾已经不在那里了,那里放着一卷纸(被覆盖了数据)。
- int& Count4() {
- int n = 0;
- n++;
- //....
- return n;
- }
-
- void Func() {
- int x = 100;
- }
-
- int main() {
- int& ret = Count4();
- cout << ret << endl;
- Func();
- cout << ret << endl;
- return 0;
- }
运行结果:

为什么在调用Func函数后,ret就变成了100了?
此时的Func函数中所开辟的栈帧位置就是之前Count4函数的栈帧位置, Count4函数被销毁,里面的整型变量n也还给了操作系统,而后Func开辟栈帧,里面同样也是开辟了一个整型变量,与n同样大小,原来变量n的所处空间被OS复用给了Func函数,其空间原有的数值被变量x所覆盖,那么意味着这块空间属于变量x了,又因为之前ret被定义为是这块空间的别名,所以ret的值也就变成了100。
- int& Count4() {
- int n = 0;
- n++;
- //....
- cout <<"变量n的地址:"<< & n << endl;
- return n;
- }
- void Func() {
- int x = 100;
- cout << "变量x的地址:" << &x << endl;
- }
-
- int main() {
- int& ret = Count4();
- cout << ret << endl;
- cout <<"ret的地址:"<< & ret << endl; //取ret的地址
- cout << endl; //换行
-
- Func();
- cout << ret << endl;
- cout << "调用Func后ret的地址:" << &ret << endl; //取ret的地址
- return 0;
- }
结果:

我们发现: 变量n的地址与变量x的地址完全一样,而调用各函数后,ret的地址也是相同的,更加印证了之前的推论,所以引用返回不能这样使用,ret的地址不可与函数中变量的地址相同!!!
1.出了作用域,且返回的变量不存在,不可用引用返回,因为引用返回导致的结果是不确定的。只能用传值返回。
2.出了作用域且返回的变量仍存在,才可以用引用返回。
- //返回的正确玩法1:
- int Count5() {
- int n = 0;
- cout << &n<< endl;
- n++;
- return n;
- }
-
- int main() {
- int ret = Count5();
- cout << ret << endl;
- cout << &ret << endl;
- return 0;
- }
运行结果:

-
- int& Count6() {
- static int n = 0;
- cout << &n << endl;
- n++;
- return n;
- }
-
- int main() {
- int ret = Count6();
- cout << ret << endl;
- cout << &ret << endl;
- return 0;
- }
运行结果:

例:创建一个结构体,里面开辟10000个整型元素的数组(相当于开辟了4w字节),我会通过值返回和引用返回去比较他俩执行的速度快慢:
- #include
- #include
- using namespace std;
-
- struct A { int a[10000]; };
- A a;
- // 值返回
- A TestFunc1(){ return a; }
-
- // 引用返回
- A& TestFunc2() { return a; }
- void TestReturnByRefOrValue()
- {
- // 以值作为函数的返回值类型
- size_t begin1 = clock();
- for (size_t i = 0; i < 100000; ++i)
- TestFunc1();
- size_t end1 = clock();
- // 以引用作为函数的返回值类型
- size_t begin2 = clock();
- for (size_t i = 0; i < 100000; ++i)
- TestFunc2();
- size_t end2 = clock();
- // 计算两个函数运算完成之后的时间
- cout << "TestFunc1 time:" << end1 - begin1 << endl;
- cout << "TestFunc2 time:" << end2 - begin2 << endl;
- }
-
- int main() {
- TestReturnByRefOrValue();
- }
运行结果:

从代码调试结果可得:引用返回所消耗的时间为1毫秒,而传值返回所消耗的时间是156毫秒,两者对比下来,引用返回要比值返回效率高很多。