RVO和NRVO优化+C++11移动操作员

RVO and NRVO optimisations + C++11 move operator

本文关键字:移动 操作员 +C++11 优化 NRVO RVO      更新时间:2023-10-16

我正试图弄清楚RVO和NRVO如何与新的C++11移动运算符一起工作。我草拟了一个有几个例子的模拟课堂。

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

这里提供完整的源代码。

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

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

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

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

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

函数返回一个引用(左值),它不能执行移动赋值,因为参数不是右值。

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

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

您有:

// 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。因此,我们使用对m11的左值引用来初始化m12。在这种情况下,编译器不能调用move构造函数,因为它需要一个右值,正如我们刚刚看到的,您提供的是一个左值。复制构造函数被调用。

另一种情况类似。你有

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

这就是所谓的

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

如上所述,这里既没有RVO也没有NRVO,因为您正在返回参数的名称。

函数按值返回,而您正在返回一个左值。(在某些情况下,编译器可以将返回的左值视为右值,但在这种情况下不允许。)因此,不能调用move构造函数,而是调用copy构造函数。