哪个功能结构更好?

时间:2011-10-26 03:20:16

标签: c++ c++11 rvalue-reference nrvo

请查看以下代码:

class MyClass{
public:
    MyClass(){}
    MyClass(MyClass &&){}
    MyClass(const MyClass &){}
};
MyClass f1(){
    MyClass &&o=MyClass();
    /*...*/
    return std::move(o);//or return static_cast<MyClass &&>(o);
}
MyClass f2(){
    MyClass o=MyClass();
    /*...*/
    return o;
}


int main(int, char **){
    auto a=f1();
    auto b=f2();
}

函数f2是返回对象的常规形式。 NRVO可能适用,并且可以避免额外的复制构造函数调用。 f1是使用右值引用的新表单。对于不支持NRVO但支持右值引用的系统,调用移动构造函数而不是复制构造函数,在大多数情况下这被认为是更好的。

f1的问题在于:在这种情况下是否有任何支持NRVO的编译器?毕竟,它似乎是未来更好的形式。

2 个答案:

答案 0 :(得分:4)

  

在这种情况下是否有NRVO的编译器支持?

定义“编译器支持”?

f1所做的是完全破坏编译器优化MyClass副本的能力。让我们详细看一下f1

MyClass &&o=MyClass();

这会创建临时,而不是堆栈变量。然后,临时绑定到名为o的r值引用,它将临时的生命周期延长到函数的末尾。

return std::move(o); //or return static_cast<MyClass &&>(o);

这将返回对临时堆栈绑定的r值引用的r值引用。因为你要返回一个值而不是一个引用,所以编译器必须从中创建一个临时值。

将省略临时复制/移动到a。但是你仍然创建了两个临时值(原始值和返回值)。

所以f1执行以下操作:

create temporary
copy/move from temporary to return value
elide copy/move from return value to `a`.

f2

create stack variable
elide copy/move from stack variable to `b`.

如果NVRO不存在,您有:

create stack variable
copy/move from stack variable to return value
elide copy/move from stack variable to `b`.

因此,f2 最差等于f1。而且更有可能,更好。

请停止尝试超越编译器。只是让复制精灵完成它的工作。

答案 1 :(得分:2)

这是当前编译器(MSVC10 / gcc trunk)的工作原理:
假设MyClass是可移动的

f1 : move   
f2 :   
worst case : move 
best case : NRVO 

假设MyClass不可移动:

f1 : copy    
f2 :    
worst case : copy    
best case : NRVO 

因此,即使编译器变得更好并开始为f1之类的函数执行NRVO,当f2经典C ++ 03函数已经达到最优时,为什么还要使代码复杂化呢?