首页 > 代码库 > 参数返回值及NRV优化(named return value optimization)

参数返回值及NRV优化(named return value optimization)

C++11中的移动构造函数又把NRV优化翻出来了,都是采用临时中间值优化,两者不能共存。

参数传递如何实现?

【实现模型1】引入临时对象,使用拷贝构造函数初始化。然后利用bitwise copy将其拷贝到x0的位置。比如:
void foo( X x0 );
X xx;
foo( xx );
改写成
X __temp0;
__temp0.X::X ( xx );
foo( __temp0 );还有一件事需要做,修改foo的声明,可以避免bit-wise copy的那一步。
void foo( X& x0 );
也就是生成一个临时对象,然后调用拷贝构造函数用实参初始化这个临时对象。然后往函数里传递这个临时对象的引用。
【实现模型2】直接在程序栈上的活动记录里进行拷贝构造。 
返回值如何实现?
【实现模型1】cfont的实现采用了双阶段转化。1.首先声明一个额外的参数,类型上类对象的引用,用来存放返回结果。2.对这个参数利用返回值进行拷贝初始化。过程类似于参数传递,也是要定义一个临时对象,用来保存返回值,然后在函数内部调用拷贝构造函数用那个return值进行初始化。
X bar()
{
   X xx;
   // process xx ...
   return xx;
}
编译器转化后
// function transformation to reflect
// application of copy constructor
// Pseudo C++ Code
void bar( X& __result )
{
   X xx;
   // compiler generated invocation
   // of default constructor
   xx.X::X();
   // ... process xx
   // compiler generated invocation
   // of copy constructor
   __result.X::X( xx );
   return;
}
 
 
【实现模型2】Named Return Value (NRV) optimization,具名返回值优化,实现这种优化有个前提,就是必须提供copy constructor,因为NRV优化的目的就是为了剔除copy constructor的使用。只有有了才能被剔除,否则谈不上剔除。一般的如果不优化NRV,其实现就是类似于模型1中的过程,而实现了优化的过程则上这样的。
X bar()
{
   X xx;
   // ... process xx
   return xx;
}
__result is substituted for xx by the compiler:
void bar( X &__result )
{
   // default constructor invocation
   // Pseudo C++ Code
   __result.X::X();
   // ... process in __result directly
   return;
}  
是否需要拷贝构造函数呢?
【注意】一方面要考虑默认的语义是否符合我们的需要。另一方面如果对象面临大量的拷贝操作,有必要实现一个拷贝构造函数以支持NRV优化。但是如果想使用底层的memcpy之类的直接进行bit wise copy,注意是否真的是bit wise copy拷贝,比如如果是virtual,这样可能破坏调vptr。
Named Return value 优化:
nrv优化的本质是优化掉拷贝构造函数,去掉它不是生成它。当然了,因为为了优化掉它,前提就是它存在,也就是欲先去之,必先有之,这个也就是nrv优化需要有拷贝构造函数存在的原因。 nrv优化会带来副作用,目前也不是正式标准,倒是那个对象模型上举的应用例子看看比较好。极端情况下,不用它的确造成很大的性能损失,知道这个情况就可以了。  
为什么必须定义了拷贝构造函数才能进行nrv优化?首先它是lippman在inside c++ object mode里说的。那个预先取之,必先有之的说法只是我的思考。查阅资料,实际上这个可能仅仅只是cfont开启NRV优化的一个开关。 
The C++ standard allows the elision of the copy constructor (even if this results in different program behavior), which has a side effect of enabling the compiler to treat both objects as one。也就是我说的副作用,c++标准允许这个副作用的出现,也就是它允许进行NRV优化,但不是必须。 
看下vc++8.0的NRV描述:http://msdn.microsoft.com/en-us/library/ms364057(VS.80).aspx
(里面说了在vc++ 8.0才加入了NRV优化,NRV优化的开关是有/O后面的级别开启。g++到底有没有,依上面的结果则是没有nrv优化) 
The Visual C++ 8.0 compiler makes use of the flexibility that the standard provides and adds a new feature: Named Return Value Optimization (NRVO). NRVO eliminates the copy constructor and destructor of a stack-based return value. This optimizes out the redundant copy constructor and destructor calls and thus improves overall performance. It is to be noted that this could lead to different behavior between optimized and non-optimized programs (see the Optimization Side Effects section). 

参数返回值及NRV优化(named return value optimization)