【问题标题】:Which function structure is better?哪种功能结构更好?
【发布时间】:2011-10-26 03:20:15
【问题描述】:

看下面的代码:

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的编译器?毕竟这似乎是未来更好的形式。

【问题讨论】:

  • "对于不支持 NRVO 但支持右值引用的系统" 我强烈怀疑这样的系统实际上并不存在。我想确认一下。
  • ooohhh... “哪个更好?” - 这是一个决定性地结束所有“哪个更好,a还是b?”的问题。问题,对吗??? (提示:选择一个更具描述性的标题)
  • C++11 的设计者们竭尽全力让最明显的代码也成为最好的代码。见stackoverflow.com/questions/4986673/…

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


【解决方案1】:

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

定义“编译器支持”?

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

MyClass &&o=MyClass();

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

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

这会将堆栈绑定的右值引用返回到临时的右值引用。而且由于您返回的是一个值,而不是一个引用,编译器必须从中创建一个临时值。

将忽略临时复制/移动到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。而且很有可能更好。

请停止试图超越编译器。让复制省略来完成它的工作。

【讨论】:

  • 你说的不对。我指定返回值是一个 MyClass 对象,因此编译器必须返回引用的副本,而不是返回要立即销毁的对象引用。在这种情况下,我的编译器清楚地调用了移动构造函数。
  • @EarthEngine:很公平。但这并不能改变你没有从中得到任何东西的事实。查看我的编辑。
【解决方案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 函数已经是最优的,为什么还要让代码复杂化呢?

【讨论】:

    猜你喜欢
    • 2012-02-16
    • 1970-01-01
    • 2021-03-30
    • 1970-01-01
    • 2010-10-18
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多