RVO和NRVO优化+ C ++ 11移动运算符

时间:2013-12-03 15:53:01

标签: c++ c++11 move-semantics rvo nrvo

我试图弄清楚RVO和NRVO如何与新的C ++ 11移动运算符一起工作。 我已经用一些例子起草了一个虚拟课程。

编辑:只显示代码中最重要的部分。

完整的源代码可用here

我有两个函数将类作为引用并返回值或引用:

VOpt& fChangeClassRetRef(VOpt &m) {
    m.setX(21);
    return m;
}

VOpt fChangeClassRetValue(VOpt &m) {
    m.setX(21);
    return m;
}

当我调用这些函数时,我输出如下:

VOpt &m14 = fChangeClassRetRef(m13);

m14 = fChangeClassRetRef(m11);
     -> Copy Assignment Operator

m14 = fChangeClassRetValue(m11);
     -> Copy Constructor
     -> C++11 Move Operator

使用左值引用时,不会调用复制构造函数。否则,那些函数(接收引用作为参数)仍然会调用复制构造函数。

此功能编译器是否依赖?我做错了吗?

2 个答案:

答案 0 :(得分:3)

m14 = fChangeClassRetRef(m11);
     -> Copy Assignment Operator

该函数返回一个引用(左值),它不能执行move-assignment,因为参数不是rvalue。

m14 = fChangeClassRetValue(m11);
     -> Copy Constructor
     -> C++11 Move Operator

在内部触发复制构造函数以创建返回的值。它必须是复制构造函数而不是移动构造函数,因为参数是引用(左值)。将返回值赋值给m14使用移动赋值运算符,因为参数是右值。

答案 1 :(得分:1)

你有:

// Change the value of the class, return ref!
VOpt& fChangeClassRetRef(VOpt &m) {
    m.setX(21);
    return m; //#1
}

以这种方式使用:

// VOpt m11;
VOpt m12 = fChangeClassRetRef(m11); // #2

让我们分析一下:#1返回一个参数的名称(不是局部变量),因此这里既不适用RVO也不适用NRVO。现在fChangeClassRetRef会返回m绑定到的位置的引用,其中#2为m11。因此,我们使用左值m12初始化m11。在这种情况下,编译器不能调用移动构造函数,因为它需要一个rvalue,正如我们刚才看到的那样,你提供了一个左值。调用复制构造函数。

另一种情况类似。

VOpt fChangeClassRetValue(VOpt &m) {
    m.setX(21);
    return m;
}

以这种方式调用:

// VOpt m13; 
VOpt &m14 = fChangeClassRetRef(m13);

如上所述,这里既没有RVV,也没有NRVO,因为你要返回一个参数的名字。

函数按值返回,您将返回左值。 (在某些情况下,允许编译器将返回的左值视为rvalue,但不是在这种情况下。)因此无法调用move构造函数并调用复制构造函数。