博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

[zz]命名返回值优化

Posted on 2012-02-25 20:30  wangwangkunkun  阅读(242)  评论(0编辑  收藏  举报

http://blog.sina.com.cn/s/blog_4ab8464c0100kybj.html

今天突然想到一个问题,如果在函数fun中定义一个局部对象a,然后返回该局部对象a给调用函数main,会不会专门为返回值再生成一个对象?
即如以下代码所示,一共会调用多少次构造函数和析构函数呢?
class A
{
public:
A(){cout<<"constructor"<<endl;};
A(const A & a){cout<<"copy constructor"<<endl;};
~A(){cout<<"destructor"<<endl;};
};
A fun()
{
cout<<"in fun"<<endl;
A a;
cout<<"returning fun"<<endl;
return a;
}
int main()
{
cout<<"in main"<<endl;
A a=fun();
cout<<"returning main"<<endl;
return 0;
}
一开始我认为这段程序至少需要调用两次构造函数生成两个对象,分别是
fun: A a;
main: A a=fun();
疑惑的是在fun返回a的时候,会不会构造一个返回值对象?
使用G++ 4.4进行编译,g++ testReturn.cpp
执行,打印结果:
in main
in fun
constructor
returning fun
returning main
destructor
居然只调用了一次构造函数!!!
而且构造函数是在fun中调用,析构函数是在main中调用
显然,g++进行了编译优化直接使用了fun()的返回对象,而没有在main中构造新的对象
但是,如果我在构造函数中有很重要的事情要做呢,比如需要new 一个对象啥的,那该怎么办呢
去掉g++的编译优化选项?g++ -O0 testReturn.cpp
得到的结果仍然是:
in main
in fun
constructor
returning fun
returning main
destructor
google了一下,发现这是一个称为命名返回值优化的问题,而且g++的这个编译优化竟然没有直接的关闭方法,在一个163博客上看到了相关线索,提到了

Joe Buck <Joe.Buck@synopsys.COM> writes:

> On Wed, Nov 07, 2007 at 07:48:53AM -0800, Ian Lance Taylor wrote:
> > "Debarshi Sanyal" <debarshisanyal@gmail.com> writes:
> >
> > > Is there any way to turn off "named return value optimization"
> > > (NRVO) while compiling a C++ program with g++?
> >
> > This question is not appropriate for gcc@gcc.gnu.org, which is for
> > developers of gcc. It is appropriate for gcc-help@gcc.gnu.org.
> > Please take any followups to that mailing list. Thanks.
> >
> > The answer to your question is no. g++ will always implement NRVO
> > when possible.
>
> You forgot about -fno-elide-constructors , Ian. I've needed it in
> the past to work around a bug in profiling; there's a PR for this.

Ah, tricky. Thanks.

Ian

尝试了一下,g++ -fno-elide-constructors testReturn.cpp ,执行结果:
in main
in fun
constructor
returning fun
copy constructor
destructor
copy constructor
destructor
returning main
destructor
终于看到main中的拷贝构造函数了!
不过在fun返回的时候,程序并没有构造一个返回值对象,因此只调用了两次构造函数