(1)以引用返回函数值,定义函数时需要在函数名前加 &

(2)用引用返回一个函数值的最大好处是,在内存中不产生被返回值的副本。

引用作为返回值,必须遵守以下规则:

  • (1)不能返回局部变量的引用。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态。
#include <iostream>
using namespace std;int& test1()
{int n = 5;return n;
}int main()
{int i = test1();cout << i << endl;  return 0;
}

g++ 5.4.0 编译报警告,运行报段错误!

VS2015编译报:warning C4172: 返回局部变量或临时变量的地址: n

但可正常运行输出

因为局部变量n赋值给i时还没有被新数据覆盖。

由此可看出g++更加严谨,不能返回局部变量的引用!

补充:

#include <iostream>
using namespace std;int& test1()
{int n = 5;return n;
}int main()
{// int i = test1();   //  因为有拷贝操作,g++5.4.0运行将会报段错误int &i = test1();  //  因为无拷贝操作,g++5.4.0运行将不会报错// cout << i << endl; // g++5.4.0运行将会报段错误return 0;
}

再举1例:

#include <iostream>
using namespace std;int& test1()
{int n = 5;return n;
}void test2()
{int b = 8;
}int main()
{int &i = test1();cout << i << endl;  // 输出 5int &b = test1();cout << b << endl;  // 输出 5test2();cout << b << endl;  // 输出 8int c = test1();test2();cout << c << endl;  // 输出 5return 0;}

VS2015编译报警告:warning C4172: 返回局部变量或临时变量的地址: n

但可正常运行输出:

i实际为test1 中局部变量的别名, 当test1退出时,i 指向的内存中值未被覆盖,直接输出为5;
输出第二个b 之前,因为调用了test2, 实际指向的内存空间已被覆盖为8,故输出为8;
c是一个新的变量,其值为5, 故输出为5;

g++ 5.4.0编译警告,运行报段错误:

  • (2)不能返回函数内部new分配的内存的引用。虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是作为一 个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak。
  • (3)可以返回类成员的引用,但最好是const。主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常 量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。

1. 用返回值方式调用函数

#include <iostream>
using namespace std;int g_a; // 定义全局变量g_aint test() {g_a = 168;return g_a;
}int main()
{int i = test();cout << i << endl; return 0;
}

返回全局变量g_a的值时,C++会在内存中创建临时变量并将g_a的值拷贝给该临时变量。当返回到主函数main后,赋值语句 i = test()会把临时变量的值再拷贝给变量i 。

2. 用函数的返回值初始化引用变量

#include <iostream>
using namespace std;int g_a; // 定义全局变量g_aint test() {g_a = 168;return g_a;
}int main()
{int &i = test();cout << i << endl; return 0;
}

编译报错:error C2440: “初始化”: 无法从“int”转换为“int &”

注:(有些编译器可以成功编译,但会给出一个warning)

分析:这种情况下,函数test()是以值方式返回,返回时,首先拷贝g_a的值给临时变量。返回到主函数后,用临时变量来初始化引用变量i,使得i成为该临时变量的别名。由于临时变量的作用域短暂(在C++标准中,临时变量或对象的生命周期在一个完整的语句表达式结束后便宣告结束,也就是在语句int &i = test();之后) ,所以i面临无效的危险,很有可能以后的值是个无法确定的值。哪怕修改为如下代码:

#include <iostream>
using namespace std;int g_a; // 定义全局变量g_aint test() {g_a = 168;return g_a;
}int main()
{const int &i = test();cout << i << endl; return 0;
}

 虽然编译运行通过,但该问题依然存在!

如果真的希望用函数的返回值来初始化一个引用变量,应当先创建一个变量,将函数的返回值赋给这个变量,然后再用该变量来初始化引用:

int b = test();
int &i = b;

3. 用返回引用的方式调用函数

#include <iostream>
using namespace std;int g_a; // 定义全局变量g_aint& test() {g_a = 168;return g_a;
}int main()
{int i = test();cout << i << endl; return 0;
}

这种情况下,函数test()的返回值不产生副本,而是直接将变量g_a返回给主函数,即主函数的赋值语句中的左值是直接从变量g_a中拷贝而来(也就是说i只是变量g_a的一个拷贝而非别名) ,这样就避免了临时变量的产生。尤其当变量g_a是一个用户自定义的类的对象时,这样还避免了调用类中的拷贝构造函数在内存中创建临时对象的过程,提高了程序的时间和空间的使用效率。

4. 用函数返回的引用作为新引用变量的初始化值

#include <iostream>
using namespace std;int g_a; // 定义全局变量g_aint& test() {g_a = 168;return g_a;
}int main()
{int &i = test();cout << i << endl; return 0;
}

这种情况下,函数test()的返回值不产生副本,而是直接将变量g_a返回给主函数。在主函数中,引用变量i用该返回值初始化,也就是说此时i成为变量g_a的别名。由于g_a是全局变量,所以在i的有效期内g_a始终保持有效,故这种做法是安全的。

5. 可以用函数返回的引用作为赋值表达式中的左值

当函数返回一个引用时,则返回一个指向返回值的隐式指针。这样,函数就可以放在赋值语句的左边。例如,请看下面这个简单的程序:

#include <iostream>
using namespace std;double vals[] = { 10.1, 12.6, 33.1, 24.1, 50.0 };double& setValues(int i)
{return vals[i];   // 返回第 i 个元素的引用
}// 要调用上面定义函数的主函数
int main()
{cout << "改变前的值" << endl;for (int i = 0; i < 5; i++){cout << "vals[" << i << "] = ";cout << vals[i] << endl;}setValues(1) = 20.23; // 改变第 2 个元素setValues(3) = 70.8;  // 改变第 4 个元素cout << "改变后的值" << endl;for (int i = 0; i < 5; i++){cout << "vals[" << i << "] = ";cout << vals[i] << endl;}return 0;
}

输出:

有兴趣可以看下:为什么 C++ 有指针了还要引用?

参考链接:http://www.runoob.com/cplusplus/returning-values-by-reference.html

C++ 引用作为函数返回值相关推荐

  1. C++ 笔记(15)— 引用(声明引用、引用作为参数、引用作为函数返回值、const 用于引用)

    引用是变量的别名.也就是说,它是某个已存在变量的另一个名字.一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量. 1. 创建引用 要声明引用,可使用引用运算符 & ,如下面的 ...

  2. “引用作为函数参数”与 “引用作为函数返回值”

    一.引用作为函数参数 作为函数参数时引用有两种原因: 1.在函数内部会对此参数进行修改:2.提高函数调用和运行效率. 关于第一点,都知道C++里提到函数就会提到形参和实参.如果函数的参数实质就是形参, ...

  3. c++_函数返回值,引用作为函数返回值

    catalog 函数返回值 返回值是`[const] T &` 返回值的类型是 T 返回的对象是 局部对象 实现原理 返回的对象是 全局对象 实例 函数返回值 返回值是[const] T &a ...

  4. C++将“引用”作为函数返回值类型的格式、好处和注意事项?

    格式: 类型标识符 &函数名(形参列表及类型说明){ //函数体 } 好处: 在内存中不产生被返回值的副本:(注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的.因为随着该局部变量生 ...

  5. 引用之函数返回值 函数的返回值为引用类型《三》

    一: 可以把函数定义为引用类型,这时函数的返回值即为某一变量的引用(别名),因此,它相当于返回了一个变量,所以可对其返回 值进行赋值操作.这一点类同于函数的返回值为指针类型. 由于函数调用返回的引用类 ...

  6. C++右值引用与函数返回值

    大一的时候在matrix上打的一道题目, 出现了迷之BUG, 后来请教了助教, 是右值引用的问题. bool operator != (simple_iterator &a) {return ...

  7. 函数返回值是否使用引用类型的问题:理解引用、返回值

    在<对象更有用的玻璃罩--常引用>一文中,介绍了对象作为函数的参数时,推荐使用引用的形式.并且,如果实际参数的值不允许改变时,声明为常引用更佳. 在<第8周-任务1-方案3-复数类中 ...

  8. 2020-09-22C++学习笔记之引用1(1.引用(普通引用)2.引用做函数参数 3.引用的意义 4.引用本质5.引用结论 6.函数返回值是引用(引用当左值)7测试代码)

    2020-09-22C++学习笔记之引用1(1.引用(普通引用)2.引用做函数参数 3.引用的意义 4.引用本质5.引用结论 6.函数返回值是引用(引用当左值)7测试代码) 1.引用(普通引用) 变量 ...

  9. 14. 函数返回值为引用?

    函数返回值可以是引用吗? 当然可以,只是在函数返回引用的时候需要注意几点.以下给出讨论! 函数在返回值的时候,会产生一个临时变量作为函数返回值的副本:而函数在返回引用的时候,不会产生副本!那么既然是引 ...

最新文章

  1. Microsoft 的 OpenSource Licence
  2. 打开网站太慢linux如何检查,seo优化中网站访问慢的检测方法
  3. how to sell products on opensea
  4. Linux 0.00 代码解析(一)
  5. 浅谈Jfinal急速开发框架
  6. C#GridViewExport帮助类,美化导出
  7. 从豌豆荚百度撕逼中学作文
  8. Web Service 移除 xmlns
  9. 利用PLTS对F域测试数据做“AFR”指南
  10. P2P(对等网络)、 PT 下载与 BT 下载
  11. 一个简单的例子开启Spark机器学习
  12. 想自学PLC编程该按什么步骤来?
  13. 德·摩根定律的验证(De Morgan’s Laws)
  14. 英语语法总结_02 名词词组与代名词
  15. ubuntu Qt 找不到 -lGL
  16. 阿里云国际版账号如何申请
  17. 申请基于GPT-4.0模型的NewBing秒审核
  18. 浏览器如何对SSL证书进行验证?
  19. 跟随大咖修炼运营圈求生欲:从案例中学习,进阶高级运营
  20. 迪博·中国上市公司内部控制指数(2000-2020年)

热门文章

  1. Unity真实榴弹炮模拟(真正的大型榴弹炮实现)
  2. 探索者Arduino模拟红外避障小车
  3. 今日头条校园招聘历年经典面试题汇总:C++研发岗
  4. 写了一半的微信订阅号
  5. 计算机组成原理--计算机的运算方法
  6. javascript国际化_如何在JavaScript中实现国际化(i18n)
  7. 死锁问题的出现和解决
  8. 学习linux的网站
  9. 补齐AI人才短板!百度飞桨师资培训高校行走进天津大学
  10. Mr.Xiong使用jQuery实现一到一百随机数和事件的委派的效果