命名返回值优化和成员初始化队列

命名返回值优化

对于一个如foo()这样的函数,它的每一个返回分支都返回相同的对象,编译器 有可能对其做Named return Value优化(下文都简称NRV优化),方法是以一个参 数result取代返回对象。

foo()的原型:

X foo() 
{ 
    X xx; 
    if(...) 
        returnxx; 
    else 
        returnxx; 
}

优化后的foo()result取代xx

void  foo(X &result)
{
    result.X::X();
    if(...)
    {
        //直接处理result
        return;
    }
    else
    {
        //直接处理result
        return;
    }
}

对比优化前与优化后的代码可以看出,对于一句类似于X a = foo()这样的代 码,NRV优化后的代码相较于原代码节省了一个临时对象的空间(省略了xx),同 时减少了两次函数调用(减少xx对象的默认构造函数和析构函数,以及一次拷贝 构造函数的调用,增加了一次对a的默认构造函数的调用)。

注:Lippman在《深度探索C++》书中指出NRV的开启与关闭取决于是否有显式定 义一个拷贝构造函数,我实在想不出有什么理由必须要有显示拷贝构造函数才能 开启NRV优化,于是在vs2010中进行了测试,测试结果表明,在release版本中, 不论是否定义了一个显式拷贝构造函数,NRV都会开启。由此可见vs2010并不以 是否有一个显式拷贝构造函数来决定NRV优化的开启与否。但同时,立足于这一 点,可以得出Lippman所说的以是否有一个显式定义的拷贝构造函数来决定是否 开启NRV优化,应该指的是他自己领导实现的cfront编译器,而非泛指所有编译 器。那么cfront又为什么要以是否定义有显示的拷贝构造函数来决定是否开启 NRV优化呢?我猜测,他大概这样以为,当显式定义有拷贝构造函数的时候一般 代表着要进行深拷贝,也就是说此时的拷贝构造函数将费时较长,在这样的情况 下NRV优化才会有明显的效果。反之,不开启NRV优化也不是什么大的效率损失。

另外,有一点要注意的是,NRV优化,有可能带来程序员并不想要的结果,最明 显的一个就是——当你的类依赖于构造函数或拷贝构造函数,甚至析构函数的调用 次数的时候,想想那会发生什么。由此可见、Lippman的cfront对NRV优化抱有更 谨慎的态度,而MS显然是更大胆。

成员初始化队列(Member Initialization List)

对于初始化队列,我相信厘清一个概念是非常重要的:在构造函数中对于对象 成员的初始化发生在初始化队列中——或者我们可以把初始化队列直接看做是对 成员的定义,而构造函数体中进行的则是赋值操作。所以不难理解有四种情况 必须用到初始化列表:

  • 有const成员
  • 有引用类型成员
  • 成员对象没有默认构造函数
  • 基类对象没有默认构造函数

前两者因为要求定义时初始化,所以必须明确的在初始化队列中给它们提供初 值。后两者因为不提供默认构造函数,所有必须显示的调用它们的带参构造函 数来定义即初始化它们。

显而易见的是当类中含有对象成员或者继承自基类的时候,在初始化队列中初 始化成员对象和基类子对象会在效率上得到提升——省去了一些赋值操作嘛。

最后,一个关于初始化队列众所周知的陷阱,初始化队列的顺序,请参考《C++ primer》或者《深度探索C++对象模型》。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值