哪个功能结构更好

Which function structure is better?

本文关键字:更好 功能结构      更新时间:2023-10-16

看下面的代码:

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但支持右值引用的系统,调用move构造函数而不是copy构造函数,后者在大多数情况下被认为更好。

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

在这种情况下,有任何编译器支持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 does:

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。而且更有可能是更好的。

请不要再试图超越编译器。让复制省略完成它的工作。

这是当前编译器(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函数已经是最佳的时候,为什么要把代码复杂化呢?