问一个函数按值返回和按引用返回的性能问题和解决办法

r_swordsman 2010-11-10 09:17:17
第一种按值返回:
Type fun()
{
Type t;
.....
return t; // 返回时会构造一个新的Type并返回此新对象,并调用t的析构函数
}


第二种按引用返回:
Type& fun()
{
Type t;
.....
return t; // 返回T的地址,但还是会调用t的析构函数

}


第一种结果虽然正确,可是浪费了一个对象的构造和析构过程,
第二种虽然返回了地址,可是对象已经被释放了,也就是结果不对

现在我想问,我采用第二种方式来写项目中的大部分的函数,那怎么确保每次调用这个函数时,
T的构造函数会被调用, 但不会调用t的析构函数.




...全文
307 45 打赏 收藏 转发到动态 举报
写回复
用AI写文章
45 条回复
切换为时间正序
请发表友善的回复…
发表回复
ceezoo 2013-03-28
  • 打赏
  • 举报
回复
Type fun() { Type t; ..... return t; } 这样就可以了,编译器知道t需要向外传递,所以会进行优化,优化成引用传递,并且延迟t的析构函数 [虽然是多年前的帖子了,还是忍不住回复了个,可能当时的编译器没这么先进]
kingstarer 2010-11-21
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 r_swordsman 的回复:]
谢谢楼上的,

第一种,t是在函数内部创建的,所能第一种不符合
第二种,好像第二次调用该函数就不会再调用t的构造函数了,而且每次返回的都是相同的地址,
我要的是

怎么确保每次调用这个函数时,
T的构造函数会被调用, 但不会调用t的析构函数

也就是所每次都会创建一个新的t,并返回t的引用,而且t要有效,不能被释放
[/Quote]
每次返回相同地址有什么问题?你获得这个引用后会长期保存? 还是你的程序是多线程的?

至于构造函数,你可以手动调用
FrankHB1989 2010-11-11
  • 打赏
  • 举报
回复
[Quote=引用 26 楼 r_swordsman 的回复:]

能具体点给点代码么?看不明白
[/Quote]
一个示例和相关说明:
http://topic.csdn.net/u/20091027/00/112644cb-231c-43a0-a700-bddd5eb6a4cd.html。

ZongShengLee 2010-11-11
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 qq120848369 的回复:]

C/C++ code
#include <iostream>
#include <string>
#include <memory>
using namespace std;

template <class T>
auto_ptr<T> func(const T &obj)
{
return auto_ptr<T>( new T(obj) );
}

int main()
{……
[/Quote]

我觉得这样挺好的。
如果不要求每次调用构造函数,我觉得那种static变量方法也挺好的。
你要每次调用构造,而不被析构,智能new了,然后自己管理指针防止内存泄露。其实就是智能指针了,标准库的智能指针就挺好的。
hslinux 2010-11-11
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 gules 的回复:]

楼主还是先搞清一个基本概念:对象的生命周期。

你的要求是返回非静态局部对象的引用,并绕开对象生命周期的问题,这是在错误应用的基础上玩技巧。

使用C++,首先应该考虑其正确的使用方式,而不是搞所谓的语法语义的“创新”,尤其是前提错误的情况下。

至于效率问题,楼主最需要知道的是80-20法则,即使你这样达到了你的目的,你的程序的效率也提高不了,况且对于返回对象的方式(第一种方式),……
[/Quote]

+++++++++++
dukong123 2010-11-11
  • 打赏
  • 举报
回复
学习下。。。。。。。。。。。。。。。。
FrankHB1989 2010-11-11
  • 打赏
  • 举报
回复
[Quote=引用 41 楼 r_swordsman 的回复:]

lsd,那个要2010,通用性不太好

我用的是vs2005,
[/Quote]
那看起来还是用std::auto_ptr比较现实一点。
用mojo实现右值引用的源码Google了一下没找到,orz……而且比起来更复杂。
herman~~ 2010-11-11
  • 打赏
  • 举报
回复
建议返回一个类成员变量或者静态变量的引用
r_swordsman 2010-11-11
  • 打赏
  • 举报
回复
lsd,那个要2010,通用性不太好

我用的是vs2005,
gules 2010-11-10
  • 打赏
  • 举报
回复
对于复杂函数,不能施行返回值优化时,也不要想着怎么返回一个局部对象的引用(这几乎总是不正确的),你完全可以将影响性能的对象作为引用或指针型参数来传递。
r_swordsman 2010-11-10
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 gules 的回复:]
这段话你是自己想像的,还是从哪里看来的,你试过了?不要想当然。

[/Quote]
那段话,
一开始我也不知道编译器会优化,当然对于上面的简单的string cat(string a, string b)
编译器也会优化,可是实际上项目的中函数都没这么简单,所以也不会优化,

看19楼
[Quote=引用 19 楼 r_swordsman 的回复:]
不好意思,查了一下,vs2005可以优化

不过如果函数复杂点,多个return的话,优化没用
[/Quote]

至于这个 你又是怎么得出编译器会创建一个s2的拷贝并说程序挂了?

原话:
return s;
/* 这里的话,假设s的结果长度为 1G, 那么创建一个对象s2, 分配 1g的空间,没有剩余空间,程序就挂了
有的话,分配了,然后释放s 的空间, 返回 s2.


我的意思是指,在多个returb的函数中.,编译器优化不起作用的话,
就会创建s2,并且没有1g可用内存的话.程序还不挂了?返回布了,
FrankHB1989 2010-11-10
  • 打赏
  • 举报
回复
其实是缺乏move语义的原因。A. Alexandrescu很早就提出过这一点,并用复杂的模板技巧在一定程度上进行了实现,可以参考Loki里的yasli::vector。
C++0x引入move语义,使用右值引用解决这个问题。
gules 2010-11-10
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 r_swordsman 的回复:]
返回一个对象也叫创新啊?

还有你说的效率提高不了多少,
以第一种方法来说,一个连接字符串的函数并返回结果
string cat(string a, string b)
{
string s = a + b;

/*

前面性能都一样

*/

return s;
/* 这里的话,假设s的结果长度为 1G, 那么创建一个对象s2, 分配 1g的空间,没有剩余空间,程序就挂了
有的话,分配了,然后释放s 的空间, 返回 s2.

何必呢? 为什么不直接可以返回 s ?
*/
}
[/Quote]
返回一个对象不叫创新,可你不是要求返回局部对象的引用,且阻止局部对象的析构被调用吗?

你举例的这段代码是典型的可以施行NRVO的代码,且不考虑string是引用计数的,你又是怎么得出编译器会创建一个s2的拷贝并说程序挂了?
string cat(string a, string b)
{
string s = a + b;

/*

前面性能都一样

*/

return s;
/* 这里的话,假设s的结果长度为 1G, 那么创建一个对象s2, 分配 1g的空间,没有剩余空间,程序就挂了
有的话,分配了,然后释放s 的空间, 返回 s2.

何必呢? 为什么不直接可以返回 s ?
*/ 这段话你是自己想像的,还是从哪里看来的,你试过了?不要想当然。
}
r_swordsman 2010-11-10
  • 打赏
  • 举报
回复
不好意思,查了一下,vs2005可以优化

不过如果函数复杂点,多个return的话,优化没用
r_swordsman 2010-11-10
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 gules 的回复:]
楼主还是先搞清一个基本概念:对象的生命周期。

你的要求是返回非静态局部对象的引用,并绕开对象生命周期的问题,这是在错误应用的基础上玩技巧。

使用C++,首先应该考虑其正确的使用方式,而不是搞所谓的语法语义的“创新”,尤其是前提错误的情况下。

至于效率问题,楼主最需要知道的是80-20法则,即使你这样达到了你的目的,你的程序的效率也提高不了,况且对于返回对象的方式(第一种方式),现……
[/Quote]

还有你说的 rvo ,是优化吧? 我用的vs2005,反正没优化
r_swordsman 2010-11-10
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 gules 的回复:]
楼主还是先搞清一个基本概念:对象的生命周期。

你的要求是返回非静态局部对象的引用,并绕开对象生命周期的问题,这是在错误应用的基础上玩技巧。

使用C++,首先应该考虑其正确的使用方式,而不是搞所谓的语法语义的“创新”,尤其是前提错误的情况下。

至于效率问题,楼主最需要知道的是80-20法则,即使你这样达到了你的目的,你的程序的效率也提高不了,况且对于返回对象的方式(第一种方式),现……
[/Quote]

返回一个对象也叫创新啊?

还有你说的效率提高不了多少,
以第一种方法来说,一个连接字符串的函数并返回结果
string cat(string a, string b)
{
string s = a + b;

/*

前面性能都一样

*/

return s;
/* 这里的话,假设s的结果长度为 1G, 那么创建一个对象s2, 分配 1g的空间,没有剩余空间,程序就挂了
有的话,分配了,然后释放s 的空间, 返回 s2.

何必呢? 为什么不直接可以返回 s ?
*/
}



wokonglinglude 2010-11-10
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 qq120848369 的回复:]
楼上回家再读几年书,别误导人了.
[/Quote]
被弄郁闷了啊,今天吃火药了。。。。
mumuliang 2010-11-10
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 wokonglinglude 的回复:]

引用 8 楼 mumuliang 的回复:
感觉要满足你的要求需要编译器升级-_-b

顶 我也想知道能满足方法
[/Quote]

你不觉得楼主是在推进新的C++标准进程吗-__-b
gules 2010-11-10
  • 打赏
  • 举报
回复
楼主还是先搞清一个基本概念:对象的生命周期。

你的要求是返回非静态局部对象的引用,并绕开对象生命周期的问题,这是在错误应用的基础上玩技巧。

使用C++,首先应该考虑其正确的使用方式,而不是搞所谓的语法语义的“创新”,尤其是前提错误的情况下。

至于效率问题,楼主最需要知道的是80-20法则,即使你这样达到了你的目的,你的程序的效率也提高不了,况且对于返回对象的方式(第一种方式),现代编译器都会优化,google“RVO”与“NRVO”(返回值优化)吧。
qq120848369 2010-11-10
  • 打赏
  • 举报
回复
楼上回家再读几年书,别误导人了.
加载更多回复(24)

64,282

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧