catalog

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

函数返回值

返回值是[const] T &

ST operator*( ST & a, ST & b){return ST( a.data * b.data);
}
ST a, b;

当你实际使用时: ST ret = a * b;
一共会有2次的 构造函数: 一次是ret 一次是函数返回值的temp临时对象

我们知道, 这个temp临时对象, 肯定是徒劳的, 是否可以优化 把它去掉呢???


错误做法1

ST & operator*( ST & a, ST & b){return ST( a.data * b.data);
}

返回一个: 指向临时对象的(引用/指针), 这自然是错误的; 因为临时对象,马上释放, 引用已经释放的内存 报错

错误做法2

ST & operator*( ST & a, ST & b){return *( new ST( a.data * b.data));
}

当遇到a * b * a时, 此时, a * b这个对象 用户就没有得到他, 他是匿名对象, 自然也就无法释放了. 造成: 内存泄漏

错误做法3

ST & operator*( ST & a, ST & b){static ST ret( a.data * b.data);return ret;
}

当遇到: if( a * b == c * d)时, 返回值永远是true.
因为, 所有operator函数的调用, 返回值都是同一个对象ret!!!
ret的值, 为, 最后一次 调用 operator
函数的 值.
所以, if( a * b == c * d), 其实他的本质是: if( c * d == c * d) 错误


所以, 请永远不要: 试图通过返回const T & 来 减少临时对象 优化程序

返回ST &, 只有1个场景:

class ST{Obj data;Obj & get_data(){ return data;}   ' 即, 返回的这个对象, 在该函数调用前 (已经)存在了!!! '
};

如果, 就是要优化 减少临时对象, 只有1种做法:

void func_multiply( ST & a, ST & b, ST & ret){ret.data = a.data * b.data;
}
ST a, b;

当你调用时: ST ret; func_multiply( a, b, ret);

返回值的类型是 T

返回值是T的意思是: 返回值是T, 不是T * T &

返回的对象是 局部对象

ST Get(){ST ret;return ret;
}

当你调用Get();时, 总共只会产生1个对象即ret
即: 函数返回给外部的对象, 就是这个ret对象本身

即, 你ST t = Get(); 时, 右侧的这个Get()所代表的对象 就是ret本身

这里好像很难理解, 因为此时的ST t = Get();, 右侧的ret对象 已经超出了 他的作用域!!!
你应该这样理解: return语句, 并不是一个函数的结束, 函数的结束 是取决于: 函数的右括号}

ST Get(){ST ret;return ret;
}ST t = Get(), func1(), func2();

首先一点是肯定的: 接收到ret的析构函数, 就意味着: Get函数的结束

执行流程是:

  • 进入Get函数, 到return这行语句时, 将ret这个对象 本身, 返回给ST t这个对象 注意, 此时Get函数, 并没有结束!!!
    即, return就像是: 发送了一个信号, 这个信号 带着ret对象本身 返回到 原先切入点, 同时, 将ret这个对象 "标记"为: 临时对象
  • 然后, 紧接着 ,执行 func1, func2, 直到执行到;结束
  • 重点: 此时, 会返回到Get函数里, 然后遇到}, 这个ret才会 delete掉

即, return语句, 就像是Qt里的 [信号与槽], 他会跳到别的地方执行, 执行完后, 还会回来的!!!


Foo Get(){Foo a;return a;    ' 或 return Foo(); 一样的 '
};

当你外界 Foo b = Get();, 全程只有1个对象a产生!!! (只有1个析构函数, 1个无参构造函数)

首先, 这确实是非常的 不可思议!!! (但是, 逻辑来讲, 这非常的合理!!)
因为, 你的目的, 就是让 a 和 b 两个对象 是相同的; 而, 如果 能用1个对象完成, 那肯定比用2个对象完成, 要好的多

一定要牢记这个知识点!!!

ST Get(){ ST o; return o;}
vector< ST> Get(){ vector< ST> o; return 0;}' 一定要写成: '
ST ret = Get();   ' &ret == &o '
vector< ST> ret = Get(); ' &ret[0,1,2,..] == &o[0,1,2,..] '' 这里的这个=等号, 不会引发任何的 对象构造复制 '-------' 千万不要写成: '
ST ret;     ret = Get();
vector< ST> ret;  ret = Get();' 天壤差别,   造成 (对象复制) '

实现原理

暂时还不知道…
我猜可能是: 你虽然是写成ST a = Get(); vector< ST> b = Get();
但是, 其实他是会变成: ST && a = Get(); vector< ST> && b = Get();


返回的对象是 全局对象

ST g;ST Get(){return g;
}

这种写法, 和 把 ST g, 放到Get函数里, 是天壤之别的!!!

程序一开始, g的构造; 然后执行: Get();return g时, 返回的 并不是g!!!
而是会调用一次ST的构造, 即构造一个新的临时对象, 给返回回去.


反问, 如果说, 返回的就是g本身. 那么&Get()是可以的, 而且Get().set_xxx()会修改 全局变量g的值.
这个功能, 应该是: ST & Get(); 而此时是: ST Get(); 这并不符合ST Get()函数的 定义.

所以, 当ST Get(){ return obj;} 返回的obj, 是一个全局对象时, 他会构造一个临时对象 给返回


再比如说:

class Bar{Foo foo;Foo get_foo(){ return foo;}
};

当你调用 bar.get_foo();时, 返回的, 并不是bar.foo本身, 而是会构造一个(临时对象)拷贝构造, 返回回去

总之: Foo get(){ return ret;} 不管这个函数, 是全局/member函数
对于这个get(){} 函数作用域来说

  • 如果这个ret, 是这个get作用域里的, 即, ret离开get作用域 就消失, 那么: 返回值的 就是这个ret本身!!!
  • 否则, 这个ret, 离开get作用域后 依然存在, 那么, 在返回时: 不会返回ret本身, 而是会 构造一个(临时对象) 返回出去!!!

实例

ST Get(){ return ST();}ST Gett(){ return Get();}ST Gettt(){ return Gett();}

调用Gettt();时, 只会调用1次 ST的构造 (对应上面ST();)!!!
因为: 当 返回值是: 局部变量 时, 返回的就是这个对象本身.


c++_函数返回值,引用作为函数返回值相关推荐

  1. C++11 右值引用与常量左值引用保存临时变量(函数返回值)的底层分析

    右值引用保存临时变量(函数返回值)的问题 :临时变量是右值 1.普通变量接收函数返回值: 2.右值引用变量接收函数返回值: 3.用const int& 和右值引用是一样的效果,只是const ...

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

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

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

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

  4. C++11中的右值引用(对比左值引用和常引用)、移动构造函数和引用标识符

    Hello!各位同学们大家好!逗比老师最近说起来还是挺尴尬的,为什么这么说呢?因为以前我对自己的C++水平还是相当自信的,经常以"精通"来自我评价.但是最近发现自己好像对C++11 ...

  5. 常亮左值引用可以绑定右值的原因

    相关文章: 为什么常量左值引用可以绑定到右值? 根据该问题的几位答主的回答,整理成个人的理解. 从设计初衷上讲 允许引用绑定非左值的初衷在于"让传值还是传引用成为函数本身的细节,调用者不用去 ...

  6. C++(13)--函数的进阶:内联、传递引用、参数默认值、重载、函数模板

    模块化编程--函数的进阶 1.内联函数 1.1 inline基本情况 1.2 inline 的前世今生-带参的宏替换 2.传递引用(重点) 2.1引用.理由.注意事项 2.3 交换两个变量的数值 3. ...

  7. C++ 对象移动(右值引用()、移动构造函数、移动赋值运算符、引用限定函数)

    原文:对象移动(右值引用(&&).移动构造函数.移动赋值运算符.引用限定函数) 一.对象移动概述 C++11标准引入了"对象移动"的概念 对象移动的特性是:可以移动 ...

  8. C++入门教程(四十二):函数参数使用引用

    小古银的官方网站(完整教程):http://www.xiaoguyin.com/ C++入门教程视频:https://www.bilibili.com/video/av20868986/ 目录 目录 ...

  9. java左值与右值问题_[C++11]左值、右值、左值引用、右值引用小结

    左值和右值 左值:指表达式结束后依然存在的持久对象,可以取地址,具名变量或对象 右值:表达式结束后就不再存在的临时对象,不可以取地址,没有名字. 比如 int a = b + c;,a 就是一个左值, ...

最新文章

  1. 一口气带你踩完五个 List 的大坑!
  2. 如何选择最优路径完成云原生上云?听这场阿里云特别分享【云原生技术与最佳实践】
  3. 电脑下边的任务栏不见了_正确的Windows任务栏设置,为你的操作带来便利,一起学习...
  4. LeetCode 557. 反转字符串中的单词 III(栈)
  5. ctk 组件创建 ui_创建可重复使用的UI组件的提示和技巧
  6. 【nodejs】使用put方式向后端提交数据
  7. android微博表情条,类似新浪微博EditText,可@某人,#插入话题,表情
  8. pl sql面试题_PL SQL面试问答
  9. WEB安全漏洞扫描与处理(下)——安全报告分析和漏洞处理
  10. 惠普计算机工作站,HP 笔记本计算机和移动工作站电池安全召回和更换计划
  11. Python中的re.search和re.group用法
  12. 用手机模拟加密门禁卡【不用电脑】
  13. python处理excel的时间格式_Python处理Excel使用pandas处理时间格式数据
  14. 【学习笔记】resnet-18 pytorch源代码解读
  15. 阿里云虚拟主机Nginx配置
  16. Java获取URL对应的资源
  17. ESIM模型详解与Keras代码实现
  18. Linux 下C/C++实现发送ICMP和ICMPv6(报文分析)
  19. HTML|页面结构分析
  20. Python Mac 1

热门文章

  1. php 数据图形,PHP生成数据流GIF和PNG透明图形教程及源代码
  2. 教你如何在Unity3D中快速制作自定义字体。
  3. OpenGL-利用摄像机实现三维空间漫游
  4. Marvell 88Q1010百兆PHY驱动调试
  5. 线程池参数详解及其工作原理
  6. js计算两个经纬度之间的距离
  7. 台式电脑蓝牙关了之后就开不了_有了这个小玩意儿,旧电脑也能用蓝牙
  8. java设置默认打印机_java 指定打印机 进行打印
  9. 只需简单5步,创建你的第一个Azure(微软云计算)应用
  10. 直接在手机写程序? C 和 golang 都可以!